import { c as stringEnum, i as jsonResult, o as readNumberParam, r as errorResult, s as readStringParam, u as Type } from "../../tool-helpers-CVAcqiCy.mjs";
import { getMevWalletClient, getWalletState, isBankrMode, requirePublicClient } from "../services/walletconnect-service.mjs";
import { guardedFetch } from "../services/endpoint-allowlist.mjs";
import "../services/price-service.mjs";
import { validateSwap } from "../services/safety-service.mjs";
import { hasBankrApi } from "../services/bankr-api.mjs";
import { isNativeEth, resolveTokenDecimals } from "../lib/token-decimals.mjs";
//#region extensions/crypto/src/tools/defi-swap.ts
/**
* DeFi Swap Tool — token swaps via 0x aggregator
* 
* Builds swap transactions, presents quotes, and submits via ClawnchConnect.
* Transactions above spending policy thresholds go to the user's phone.
*/
const DefiSwapSchema = Type.Object({
	action: stringEnum(["quote", "execute"], { description: "quote: get a swap quote with price impact. execute: execute the swap." }),
	token_in: Type.String({ description: "Token to sell — symbol (e.g. \"ETH\", \"USDC\") or contract address (0x...)" }),
	token_out: Type.String({ description: "Token to buy — symbol (e.g. \"ETH\", \"USDC\") or contract address (0x...)" }),
	amount: Type.String({ description: "Amount to sell (in human-readable units, e.g. \"0.1\" for 0.1 ETH)" }),
	slippage: Type.Optional(Type.Number({ description: "Max slippage percentage (default: 1.0 for 1%)" })),
	chain: Type.Optional(Type.String({ description: "Chain for the swap (default: \"base\"). Bankr mode supports: base, ethereum, polygon, unichain, solana" }))
});
const BASE_TOKENS = {
	ETH: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
	WETH: "0x4200000000000000000000000000000000000006",
	USDC: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
	USDT: "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2",
	DAI: "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
	CLAWNCH: "0xa1F72459dfA10BAD200Ac160eCd78C6b77a747be"
};
function resolveToken(input) {
	if (input.startsWith("0x") && input.length === 42) return input;
	return BASE_TOKENS[input.toUpperCase()] ?? input;
}
function createDefiSwapTool() {
	return {
		name: "defi_swap",
		label: "DeFi Swap",
		ownerOnly: true,
		description: "Swap tokens via DEX aggregator (Base) or Bankr Agent API (all chains). Get quotes with price impact and gas estimates, then execute swaps. In Bankr mode, supports Base, Ethereum, Polygon, Unichain, and Solana. Supports ETH, WETH, USDC, USDT, DAI, CLAWNCH, and any token by address or symbol.",
		parameters: DefiSwapSchema,
		execute: async (_toolCallId, args) => {
			const params = args;
			const action = readStringParam(params, "action", { required: true });
			const chain = readStringParam(params, "chain") || "base";
			if (!getWalletState().connected) return errorResult("No wallet connected. Use clawnchconnect tool to connect first.");
			if (isBankrMode() || chain !== "base" && hasBankrApi()) {
				if (!hasBankrApi()) return errorResult(`Swaps on ${chain} require Bankr wallet. Connect via /connect_bankr first.`);
				return action === "quote" ? handleBankrQuote(params, chain) : handleBankrSwap(params, chain);
			}
			if (chain !== "base") return errorResult(`Swaps on ${chain} are not supported without Bankr wallet. Connect via /connect_bankr to access multi-chain swaps.`);
			switch (action) {
				case "quote": return handleQuote(params);
				case "execute": return handleExecute(params);
				default: return errorResult(`Unknown action: ${action}`);
			}
		}
	};
}
const SAFE_TOKEN_RE = /^[a-zA-Z0-9_.\-\/]{1,60}$/;
const SAFE_ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;
const SAFE_AMOUNT_RE = /^[0-9][0-9,._]*$/;
const SAFE_CHAIN_RE = /^[a-zA-Z0-9\-]{1,20}$/;
function sanitizeBankrToken(input) {
	const trimmed = input.trim();
	if (SAFE_ADDRESS_RE.test(trimmed) || SAFE_TOKEN_RE.test(trimmed)) return trimmed;
	throw new Error(`Invalid token: "${trimmed.slice(0, 30)}". Use a symbol (e.g. "ETH") or address (0x...).`);
}
function sanitizeBankrAmount(input) {
	const trimmed = input.trim();
	if (SAFE_AMOUNT_RE.test(trimmed)) return trimmed;
	throw new Error(`Invalid amount: "${trimmed.slice(0, 30)}". Use a number like "0.1" or "100".`);
}
function sanitizeBankrChain(input) {
	const trimmed = input.trim();
	if (SAFE_CHAIN_RE.test(trimmed)) return trimmed;
	throw new Error(`Invalid chain: "${trimmed.slice(0, 20)}".`);
}
async function handleBankrQuote(params, chain) {
	const tokenIn = sanitizeBankrToken(readStringParam(params, "token_in", { required: true }));
	const tokenOut = sanitizeBankrToken(readStringParam(params, "token_out", { required: true }));
	const amount = sanitizeBankrAmount(readStringParam(params, "amount", { required: true }));
	const safeChain = sanitizeBankrChain(chain);
	try {
		const { bankrPromptAndPoll } = await import("../services/bankr-api.mjs");
		const result = await bankrPromptAndPoll(`quote swapping ${amount} ${tokenIn} to ${tokenOut} on ${safeChain}`, { timeoutMs: 3e4 });
		if (result.status === "failed") return errorResult(`Quote failed: ${result.error ?? "Unknown error"}`);
		return jsonResult({
			source: "bankr",
			chain,
			tokenIn,
			tokenOut,
			amount,
			response: result.response,
			richData: result.richData,
			note: "Use action \"execute\" to proceed with this swap."
		});
	} catch (err) {
		return errorResult(`Bankr quote failed: ${err instanceof Error ? err.message : String(err)}`);
	}
}
async function handleBankrSwap(params, chain) {
	const tokenIn = sanitizeBankrToken(readStringParam(params, "token_in", { required: true }));
	const tokenOut = sanitizeBankrToken(readStringParam(params, "token_out", { required: true }));
	const amount = sanitizeBankrAmount(readStringParam(params, "amount", { required: true }));
	const safeChain = sanitizeBankrChain(chain);
	try {
		const { bankrPromptAndPoll } = await import("../services/bankr-api.mjs");
		const result = await bankrPromptAndPoll(`swap ${amount} ${tokenIn} to ${tokenOut} on ${safeChain}`, { timeoutMs: 12e4 });
		if (result.status === "failed") return errorResult(`Swap failed: ${result.error ?? "Unknown error"}`);
		const txData = result.transactions?.find((t) => t.type === "swap");
		return jsonResult({
			status: "success",
			source: "bankr",
			chain,
			tokenIn,
			tokenOut,
			amountIn: amount,
			txHash: txData?.hash ?? (txData?.metadata)?.transaction?.hash,
			response: result.response,
			richData: result.richData
		});
	} catch (err) {
		return errorResult(`Bankr swap failed: ${err instanceof Error ? err.message : String(err)}`);
	}
}
async function handleQuote(params) {
	const tokenIn = resolveToken(readStringParam(params, "token_in", { required: true }));
	const tokenOut = resolveToken(readStringParam(params, "token_out", { required: true }));
	const amount = readStringParam(params, "amount", { required: true });
	if (!/^\d+(\.\d+)?$/.test(amount.trim())) return errorResult(`Invalid amount: "${amount}". Must be a positive number (e.g. "1.5" or "100").`);
	const slippage = readNumberParam(params, "slippage") ?? 1;
	try {
		const { parseEther, parseUnits, formatUnits } = await import("../../_esm-BrzUp3yp.mjs").then((n) => n.t);
		const state = getWalletState();
		const isEth = isNativeEth(tokenIn);
		const publicClientForDecimals = (() => {
			try {
				return requirePublicClient();
			} catch {
				return null;
			}
		})();
		const tokenDecimals = await resolveTokenDecimals(tokenIn, publicClientForDecimals);
		const amountWei = isEth ? parseEther(amount) : parseUnits(amount, tokenDecimals);
		const { getDexAggregator } = await import("../services/dex-aggregator.mjs");
		const aggregator = getDexAggregator({ slippageBps: Math.round(slippage * 100) });
		let allQuotes = [];
		let bestQuote = null;
		try {
			allQuotes = await aggregator.getQuotes(tokenIn, tokenOut, amountWei.toString());
			bestQuote = allQuotes.filter((q) => !q.error && q.buyAmount !== "0")[0] ?? null;
		} catch {}
		if (!bestQuote) {
			const response = await guardedFetch(`${process.env.CLAWNCHER_API_URL || "https://clawn.ch"}/api/swap/quote?${new URLSearchParams({
				sellToken: tokenIn,
				buyToken: tokenOut,
				sellAmount: amountWei.toString(),
				slippagePercentage: (slippage / 100).toString(),
				takerAddress: state.address
			})}`, { headers: { Accept: "application/json" } });
			if (!response.ok) return errorResult(`Quote failed: ${await response.text()}`);
			const clawnchQuote = await response.json();
			bestQuote = {
				aggregator: "Clawnch (0x)",
				sellToken: tokenIn,
				buyToken: tokenOut,
				sellAmount: amountWei.toString(),
				buyAmount: clawnchQuote.buyAmount ?? "0",
				price: parseFloat(clawnchQuote.price ?? "0"),
				gasEstimate: clawnchQuote.estimatedGas ?? "0",
				gasPrice: clawnchQuote.gasPrice,
				route: clawnchQuote.sources?.filter((s) => s.proportion !== "0").map((s) => s.name).join(" → ") ?? "Clawnch",
				data: clawnchQuote
			};
		}
		let safety = null;
		try {
			safety = await validateSwap({
				tokenIn,
				tokenOut,
				amountEth: parseFloat(amount)
			});
		} catch {}
		const outDecimals = await resolveTokenDecimals(tokenOut, publicClientForDecimals);
		const comparison = allQuotes.filter((q) => !q.error).map((q) => ({
			aggregator: q.aggregator,
			buyAmount: formatUnits(BigInt(q.buyAmount || "0"), outDecimals),
			gasEstimate: q.gasEstimate,
			gasCostUsd: q.gasCostUsd,
			route: q.route,
			isBest: q.aggregator === bestQuote.aggregator
		}));
		return jsonResult({
			bestAggregator: bestQuote.aggregator,
			tokenIn: {
				address: tokenIn,
				amount,
				amountWei: amountWei.toString()
			},
			tokenOut: {
				address: tokenOut,
				estimatedAmount: bestQuote.buyAmount ? formatUnits(BigInt(bestQuote.buyAmount), outDecimals) : "unknown"
			},
			price: bestQuote.price,
			gas: bestQuote.gasEstimate,
			gasPrice: bestQuote.gasPrice,
			gasCostUsd: bestQuote.gasCostUsd,
			route: bestQuote.route,
			slippage: `${slippage}%`,
			comparison: comparison.length > 1 ? comparison : void 0,
			safety: safety ? {
				safe: safety.safe,
				warnings: safety.warnings,
				blockers: safety.blockers
			} : void 0,
			note: safety?.blockers.length ? "SAFETY BLOCKERS FOUND — review before executing." : "Use action \"execute\" to proceed with this swap."
		});
	} catch (err) {
		return errorResult(`Quote failed: ${err instanceof Error ? err.message : String(err)}`);
	}
}
async function handleExecute(params) {
	const tokenIn = resolveToken(readStringParam(params, "token_in", { required: true }));
	const tokenOut = resolveToken(readStringParam(params, "token_out", { required: true }));
	const amount = readStringParam(params, "amount", { required: true });
	if (!/^\d+(\.\d+)?$/.test(amount.trim())) return errorResult(`Invalid amount: "${amount}". Must be a positive number (e.g. "1.5" or "100").`);
	const slippage = readNumberParam(params, "slippage") ?? 1;
	try {
		const safety = await validateSwap({
			tokenIn,
			tokenOut,
			amountEth: parseFloat(amount)
		});
		if (!safety.safe) return errorResult(`Swap blocked by safety checks:\n` + safety.blockers.map((b) => `  ✗ ${b}`).join("\n") + (safety.warnings.length ? "\n\nWarnings:\n" + safety.warnings.map((w) => `  ⚠ ${w}`).join("\n") : ""));
		if (safety.warnings.length > 0) {}
	} catch (err) {
		console.warn("[defi-swap] Safety check failed, proceeding without validation:", err instanceof Error ? err.message : String(err));
	}
	try {
		const { ClawnchSwapper } = await import("../../dist-CXAY4yCt.mjs");
		const wallet = await getMevWalletClient();
		const publicClient = requirePublicClient();
		const swapper = new ClawnchSwapper({
			wallet,
			publicClient,
			apiBaseUrl: process.env.CLAWNCHER_API_URL || "https://clawn.ch"
		});
		const { parseEther, parseUnits } = await import("../../_esm-BrzUp3yp.mjs").then((n) => n.t);
		const isEthIn = isNativeEth(tokenIn);
		const sellDecimals = await resolveTokenDecimals(tokenIn, publicClient);
		const sellAmountWei = isEthIn ? parseEther(amount) : parseUnits(amount, sellDecimals);
		const SWAP_TIMEOUT_MS = 12e4;
		const swapPromise = swapper.swap({
			sellToken: tokenIn,
			buyToken: tokenOut,
			sellAmount: sellAmountWei,
			slippageBps: Math.round(slippage * 100)
		});
		const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error("Swap timed out after 2 minutes. The transaction may still be pending in your wallet — check Rainbow/MetaMask. If you see a pending approval or swap, you can approve or reject it there.")), SWAP_TIMEOUT_MS));
		const result = await Promise.race([swapPromise, timeoutPromise]);
		return jsonResult({
			status: "success",
			txHash: result.txHash,
			tokenIn,
			tokenOut,
			amountIn: amount,
			amountOut: result.buyAmount ? result.buyAmount.toString() : void 0,
			sellAmount: result.sellAmount?.toString(),
			gasUsed: result.gasUsed?.toString()
		});
	} catch (err) {
		const msg = err instanceof Error ? err.message : String(err);
		if (msg.includes("reverted")) return errorResult(`Swap transaction reverted on-chain. This usually means:
  - Insufficient token balance or allowance
  - Price moved beyond slippage tolerance
  - Token has transfer restrictions
  - No liquidity for this pair on supported DEXes

Try checking your balance with defi_balance, or try a smaller amount.\n\nError: ${msg}`);
		if (msg.includes("rejected") || msg.includes("declined") || msg.includes("denied")) return errorResult(`Swap cancelled — you rejected the transaction in your wallet.`);
		if (msg.includes("timed out") || msg.includes("Swap timed out")) return errorResult(msg);
		return errorResult(`Swap failed: ${msg}`);
	}
}
//#endregion
export { createDefiSwapTool };

//# sourceMappingURL=defi-swap.mjs.map