import { isDelegationMode } from "./policy-types.mjs";
import "./policy-store.mjs";
import { canRedeem, getDelegatedPolicies, redeemDelegation } from "./delegation-service.mjs";
//#region extensions/crypto/src/services/delegation-executor.ts
const RATE_LIMIT_WINDOW_MS = 6e4;
const RATE_LIMIT_MAX_ATTEMPTS = 3;
const _redemptionAttempts = /* @__PURE__ */ new Map();
function rateLimitKey(userId, toolName) {
	return `${userId}:${toolName}`;
}
function isRateLimited(userId, toolName) {
	const key = rateLimitKey(userId, toolName);
	const now = Date.now();
	return (_redemptionAttempts.get(key) ?? []).filter((t) => now - t < RATE_LIMIT_WINDOW_MS).length >= RATE_LIMIT_MAX_ATTEMPTS;
}
function recordRedemptionAttempt(userId, toolName) {
	const key = rateLimitKey(userId, toolName);
	const now = Date.now();
	const recent = (_redemptionAttempts.get(key) ?? []).filter((t) => now - t < RATE_LIMIT_WINDOW_MS);
	recent.push(now);
	_redemptionAttempts.set(key, recent);
}
/** Clear rate limit for a user+tool (call on successful redemption). */
function clearRateLimit(userId, toolName) {
	_redemptionAttempts.delete(rateLimitKey(userId, toolName));
}
const WELL_KNOWN_DECIMALS = {
	"0x833589fcd6edb6e08f4c7c32d4f71b54bda02913": 6,
	"0xfde4c96c8593536e31f229ea8f37b2ada2699bb2": 6,
	"0x50c5725949a6f0c72e6c4a641f24049a917db0cb": 18,
	"0x4200000000000000000000000000000000000006": 18,
	"0xa1f72459dfa10bad200ac160ecd78c6b77a747be": 18
};
function getTokenDecimals(address) {
	return WELL_KNOWN_DECIMALS[address.toLowerCase()] ?? 18;
}
/**
* Encode ERC-20 transfer(address,uint256) calldata.
* Selector: 0xa9059cbb
*/
function encodeErc20Transfer(to, amount) {
	return `0xa9059cbb${to.slice(2).toLowerCase().padStart(64, "0")}${amount.toString(16).padStart(64, "0")}`;
}
/**
* Encode ERC-20 approve(address,uint256) calldata.
* Selector: 0x095ea7b3
*/
function encodeErc20Approve(spender, amount) {
	return `0x095ea7b3${spender.slice(2).toLowerCase().padStart(64, "0")}${amount.toString(16).padStart(64, "0")}`;
}
/**
* Parse a human-readable token amount to wei/smallest unit.
* e.g., "100" with 6 decimals → 100_000_000n
*/
function parseTokenAmount(amount, decimals) {
	const num = parseFloat(amount);
	if (isNaN(num) || num <= 0) return 0n;
	const [whole = "0", frac = ""] = amount.split(".");
	const paddedFrac = (frac + "0".repeat(decimals)).slice(0, decimals);
	return BigInt(whole + paddedFrac);
}
const KNOWN_SWAP_TARGETS = new Set([
	"0xdef1c0ded9bec7f1a1670819833240f027b25eff",
	"0x1111111254eeb25477b68fb85ed929f73a960582",
	"0x111111125421ca6dc452d289314280a0f8842a65",
	"0xdef171fe48cf0115b1d80b88dc8eab59176fee57",
	"0x6131b5fae19ea4f9d964eac0408e4408b66337b5",
	"0x000000000022d473030f116ddee9f6b43ac78ba3"
].map((a) => a.toLowerCase()));
const KNOWN_BRIDGE_TARGETS = new Set(["0x1231deb6f5749ef6ce6943a275a1d3e7486f4eae", "0x341e94069f53234fE6DabeF707aD424830525715"].map((a) => a.toLowerCase()));
function isKnownSwapTarget(addr) {
	return KNOWN_SWAP_TARGETS.has(addr.toLowerCase());
}
function isKnownBridgeTarget(addr) {
	return KNOWN_BRIDGE_TARGETS.has(addr.toLowerCase());
}
/** Encode a signed int24 as a 32-byte ABI word (two's complement). */
function toInt24Hex(val) {
	if (val >= 0) return val.toString(16).padStart(64, "0");
	return (BigInt(2) ** BigInt(256) + BigInt(val)).toString(16).padStart(64, "0");
}
const SUPPORTED_EXTRACTORS = {
	transfer: async (args) => {
		if (args.action !== "send") return null;
		const to = args.to;
		const amount = args.amount;
		const token = args.token;
		if (!to || !amount) return null;
		if (!/^0x[0-9a-fA-F]{40}$/.test(to)) return null;
		const isErc20 = token && /^0x[0-9a-fA-F]{40}$/.test(token);
		const isNative = !token || token.toUpperCase() === "ETH" || token.toUpperCase() === "NATIVE";
		if (isErc20) try {
			const amountWei = parseTokenAmount(amount, getTokenDecimals(token));
			if (amountWei <= 0n) return null;
			return {
				target: token,
				value: 0n,
				callData: encodeErc20Transfer(to, amountWei)
			};
		} catch {
			return null;
		}
		if (isNative) try {
			const weiValue = parseTokenAmount(amount, 18);
			if (weiValue <= 0n) return null;
			return {
				target: to,
				value: weiValue,
				callData: "0x"
			};
		} catch {
			return null;
		}
		return null;
	},
	clawnchconnect: async (args) => {
		if (args.action !== "send_tx") return null;
		const to = args.to;
		if (!to || !/^0x[0-9a-fA-F]{40}$/.test(to)) return null;
		const valueStr = args.value;
		const data = args.data;
		try {
			let value = 0n;
			if (valueStr) {
				value = parseTokenAmount(valueStr, 18);
				if (value < 0n) value = 0n;
			}
			const callData = data && data.startsWith("0x") ? data : "0x";
			return {
				target: to,
				value,
				callData
			};
		} catch {
			return null;
		}
	},
	approvals: async (args) => {
		if (args.action !== "revoke") return null;
		const token = args.token;
		const spender = args.spender;
		if (!token || !spender) return null;
		if (!/^0x[0-9a-fA-F]{40}$/.test(token) || !/^0x[0-9a-fA-F]{40}$/.test(spender)) return null;
		return {
			target: token,
			value: 0n,
			callData: encodeErc20Approve(spender, 0n)
		};
	},
	permit2: async (args) => {
		if (args.action !== "approve") return null;
		const token = args.token;
		if (!token || !/^0x[0-9a-fA-F]{40}$/.test(token)) return null;
		return {
			target: token,
			value: 0n,
			callData: encodeErc20Approve("0x000000000022D473030F116dDEE9F6B43aC78BA3", 2n ** 256n - 1n)
		};
	},
	nft: async (args) => {
		if (args.action !== "transfer") return null;
		const contract = args.contract;
		const tokenId = args.token_id;
		const to = args.to;
		if (!contract || !tokenId || !to) return null;
		if (!/^0x[0-9a-fA-F]{40}$/.test(contract) || !/^0x[0-9a-fA-F]{40}$/.test(to)) return null;
		return {
			target: contract,
			value: 0n,
			callData: `0x23b872dd${"0".repeat(64)}${to.slice(2).toLowerCase().padStart(64, "0")}${BigInt(tokenId).toString(16).padStart(64, "0")}`
		};
	},
	defi_lend: async (args) => {
		const action = args.action;
		if (action !== "borrow" && action !== "withdraw" && action !== "supply" && action !== "repay") return null;
		const asset = args.asset;
		const amount = args.amount;
		if (!asset || !amount) return null;
		const assetInfo = {
			"eth": {
				address: "0x4200000000000000000000000000000000000006",
				decimals: 18
			},
			"weth": {
				address: "0x4200000000000000000000000000000000000006",
				decimals: 18
			},
			"usdc": {
				address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
				decimals: 6
			},
			"usdbc": {
				address: "0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA",
				decimals: 6
			},
			"cbeth": {
				address: "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22",
				decimals: 18
			}
		}[asset.toLowerCase()];
		const assetAddr = assetInfo?.address ?? (/^0x[0-9a-fA-F]{40}$/.test(asset) ? asset : null);
		if (!assetAddr) return null;
		const amountWei = parseTokenAmount(amount, assetInfo?.decimals ?? 18);
		if (amountWei <= 0n) return null;
		const AAVE_POOL = "0xA238Dd80C259a72e81d7e4664a9801593F98d1c5";
		if (action === "borrow") return {
			target: AAVE_POOL,
			value: 0n,
			callData: `0xa415bcad${assetAddr.slice(2).toLowerCase().padStart(64, "0")}${amountWei.toString(16).padStart(64, "0")}${2n.toString(16).padStart(64, "0")}${0n.toString(16).padStart(64, "0")}${"0".repeat(64)}`
		};
		if (action === "supply") return {
			target: AAVE_POOL,
			value: 0n,
			callData: `0x617ba037${assetAddr.slice(2).toLowerCase().padStart(64, "0")}${amountWei.toString(16).padStart(64, "0")}${"0".repeat(64)}${0n.toString(16).padStart(64, "0")}`
		};
		if (action === "repay") return {
			target: AAVE_POOL,
			value: 0n,
			callData: `0x573ade81${assetAddr.slice(2).toLowerCase().padStart(64, "0")}${amountWei.toString(16).padStart(64, "0")}${2n.toString(16).padStart(64, "0")}${"0".repeat(64)}`
		};
		return {
			target: AAVE_POOL,
			value: 0n,
			callData: `0x69328dec${assetAddr.slice(2).toLowerCase().padStart(64, "0")}${amountWei.toString(16).padStart(64, "0")}${"0".repeat(64)}`
		};
	},
	defi_stake: async (args) => {
		const action = args.action;
		const protocol = args.protocol?.toLowerCase();
		const amount = args.amount;
		if (!action || !amount) return null;
		const weiValue = parseTokenAmount(amount, 18);
		if (weiValue <= 0n) return null;
		if (action === "stake" && (!protocol || protocol === "lido")) return {
			target: "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84",
			value: weiValue,
			callData: `0xa1903eab${"0".repeat(64)}`
		};
		if (action === "stake" && protocol === "rocketpool") return {
			target: "0xDD3f50F8A6CafbE9b31a427582963f465E745AF8",
			value: weiValue,
			callData: "0xd0e30db0"
		};
		if (action === "unstake" && protocol === "rocketpool") return {
			target: "0xae78736Cd615f374D3085123A210448E74Fc6393",
			value: 0n,
			callData: `0x42966c68${weiValue.toString(16).padStart(64, "0")}`
		};
		if (action === "unwrap") return {
			target: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0",
			value: 0n,
			callData: `0xde0e9a3e${weiValue.toString(16).padStart(64, "0")}`
		};
		return null;
	},
	governance: async (args) => {
		const action = args.action;
		if (action === "vote") {
			const governor = args.governor;
			const proposalId = args.proposal_id;
			const support = args.support;
			if (!governor || !proposalId || support === void 0) return null;
			if (!/^0x[0-9a-fA-F]{40}$/.test(governor)) return null;
			return {
				target: governor,
				value: 0n,
				callData: `0x56781388${BigInt(proposalId).toString(16).padStart(64, "0")}${BigInt(support).toString(16).padStart(64, "0")}`
			};
		}
		if (action === "delegate") {
			const token = args.token;
			const delegatee = args.delegatee;
			if (!token || !delegatee) return null;
			if (!/^0x[0-9a-fA-F]{40}$/.test(token) || !/^0x[0-9a-fA-F]{40}$/.test(delegatee)) return null;
			return {
				target: token,
				value: 0n,
				callData: `0x5c19a95c${delegatee.slice(2).toLowerCase().padStart(64, "0")}`
			};
		}
		return null;
	},
	yield: async (args) => {
		const action = args.action;
		if (action !== "withdraw" && action !== "deposit") return null;
		const vault = args.vault;
		const amount = args.amount;
		if (!vault || !amount) return null;
		if (!/^0x[0-9a-fA-F]{40}$/.test(vault)) return null;
		const amountWei = parseTokenAmount(amount, 18);
		if (amountWei <= 0n) return null;
		if (action === "deposit") return {
			target: vault,
			value: 0n,
			callData: `0x6e553f65${amountWei.toString(16).padStart(64, "0")}${"0".repeat(64)}`
		};
		return {
			target: vault,
			value: 0n,
			callData: `0xb460af94${amountWei.toString(16).padStart(64, "0")}${"0".repeat(64)}${"0".repeat(64)}`
		};
	},
	liquidity: async (args, ctx) => {
		const action = args.action;
		const V3_NPM = "0x03a520b32C04BF3bEEf7BEb72E919cf822Ed34f1";
		const MAX_UINT128 = 2n ** 128n - 1n;
		const deadline = BigInt(Math.floor(Date.now() / 1e3) + 1800);
		if (action === "v3_mint") {
			const token0 = args.token0;
			const token1 = args.token1;
			const fee = Number(args.fee ?? 3e3);
			const tickLower = Number(args.tick_lower ?? 0);
			const tickUpper = Number(args.tick_upper ?? 0);
			const amount0 = args.amount0;
			const amount1 = args.amount1;
			if (!token0 || !token1 || !amount0 || !amount1) return null;
			if (!/^0x[0-9a-fA-F]{40}$/.test(token0) || !/^0x[0-9a-fA-F]{40}$/.test(token1)) return null;
			const dec0 = getTokenDecimals(token0);
			const dec1 = getTokenDecimals(token1);
			const amt0 = parseTokenAmount(amount0, dec0);
			const amt1 = parseTokenAmount(amount1, dec1);
			if (amt0 <= 0n && amt1 <= 0n) return null;
			const recipient = ctx?.walletAddress ?? "0x" + "0".repeat(40);
			return {
				target: V3_NPM,
				value: 0n,
				callData: `0x88316456${[
					token0.slice(2).toLowerCase().padStart(64, "0"),
					token1.slice(2).toLowerCase().padStart(64, "0"),
					fee.toString(16).padStart(64, "0"),
					toInt24Hex(tickLower),
					toInt24Hex(tickUpper),
					amt0.toString(16).padStart(64, "0"),
					amt1.toString(16).padStart(64, "0"),
					0n.toString(16).padStart(64, "0"),
					0n.toString(16).padStart(64, "0"),
					recipient.slice(2).toLowerCase().padStart(64, "0"),
					deadline.toString(16).padStart(64, "0")
				].join("")}`
			};
		}
		if (action === "v3_add") {
			const tokenId = args.token_id;
			const amount0 = args.amount0;
			const amount1 = args.amount1;
			if (!tokenId || !amount0 || !amount1) return null;
			const token0 = args.token0;
			const token1 = args.token1;
			const dec0 = token0 ? getTokenDecimals(token0) : 18;
			const dec1 = token1 ? getTokenDecimals(token1) : 18;
			const amt0 = parseTokenAmount(amount0, dec0);
			const amt1 = parseTokenAmount(amount1, dec1);
			return {
				target: V3_NPM,
				value: 0n,
				callData: `0x219f5d17${[
					BigInt(tokenId).toString(16).padStart(64, "0"),
					amt0.toString(16).padStart(64, "0"),
					amt1.toString(16).padStart(64, "0"),
					0n.toString(16).padStart(64, "0"),
					0n.toString(16).padStart(64, "0"),
					deadline.toString(16).padStart(64, "0")
				].join("")}`
			};
		}
		if (action === "v3_collect") {
			const tokenId = args.token_id;
			if (!tokenId) return null;
			const recipient = ctx?.walletAddress ?? "0x" + "0".repeat(40);
			return {
				target: V3_NPM,
				value: 0n,
				callData: `0xfc6f7865${[
					BigInt(tokenId).toString(16).padStart(64, "0"),
					recipient.slice(2).toLowerCase().padStart(64, "0"),
					MAX_UINT128.toString(16).padStart(64, "0"),
					MAX_UINT128.toString(16).padStart(64, "0")
				].join("")}`
			};
		}
		if (action === "v3_remove") {
			const tokenId = args.token_id;
			const percentage = Number(args.percentage ?? 100);
			if (!tokenId) return null;
			if (!ctx?.walletAddress) return null;
			try {
				const { getPublicClient } = await import("./walletconnect-service.mjs");
				const pub = getPublicClient();
				if (!pub) return null;
				const posData = await pub.call({
					to: V3_NPM,
					data: `0x99fbab88${BigInt(tokenId).toString(16).padStart(64, "0")}`
				});
				if (!posData.data || posData.data.length < 514) return null;
				const liquidityHex = posData.data.slice(450, 514);
				const totalLiquidity = BigInt("0x" + liquidityHex);
				if (totalLiquidity <= 0n) return null;
				const liquidityToRemove = totalLiquidity * BigInt(percentage) / 100n;
				const decSel = "0x0c49ccbe";
				const decFields = [
					BigInt(tokenId).toString(16).padStart(64, "0"),
					liquidityToRemove.toString(16).padStart(64, "0"),
					0n.toString(16).padStart(64, "0"),
					0n.toString(16).padStart(64, "0"),
					deadline.toString(16).padStart(64, "0")
				].join("");
				const calls = [`${decSel}${decFields}`, `0xfc6f7865${[
					BigInt(tokenId).toString(16).padStart(64, "0"),
					ctx.walletAddress.slice(2).toLowerCase().padStart(64, "0"),
					MAX_UINT128.toString(16).padStart(64, "0"),
					MAX_UINT128.toString(16).padStart(64, "0")
				].join("")}`];
				if (percentage >= 100) {
					const burnCalldata = `0x42966c68${BigInt(tokenId).toString(16).padStart(64, "0")}`;
					calls.push(burnCalldata);
				}
				return {
					target: V3_NPM,
					value: 0n,
					callData: `${decSel}${decFields}`
				};
			} catch {
				return null;
			}
		}
		return null;
	},
	defi_swap: async (args, ctx) => {
		if (args.action !== "execute") return null;
		if (!ctx?.walletAddress) return null;
		const tokenIn = args.token_in;
		const tokenOut = args.token_out;
		const amount = args.amount;
		const slippage = args.slippage ?? 1;
		if (!tokenIn || !tokenOut || !amount) return null;
		const inAddr = resolveSwapToken(tokenIn);
		const outAddr = resolveSwapToken(tokenOut);
		if (!inAddr || !outAddr) return null;
		const sellAmountWei = parseTokenAmount(amount, inAddr.toLowerCase() === NATIVE_TOKEN_ADDRESS.toLowerCase() ? 18 : getTokenDecimals(inAddr));
		if (sellAmountWei <= 0n) return null;
		try {
			const apiBase = process.env.CLAWNCHER_API_URL || "https://clawn.ch";
			const chainId = ctx.chainId ?? 8453;
			const params = new URLSearchParams({
				chainId: String(chainId),
				sellToken: inAddr,
				buyToken: outAddr,
				sellAmount: sellAmountWei.toString(),
				slippageBps: String(Math.round(slippage * 100)),
				taker: ctx.walletAddress
			});
			const controller = new AbortController();
			const timeout = setTimeout(() => controller.abort(), 5e3);
			const resp = await fetch(`${apiBase}/api/swap/quote?${params}`, {
				headers: { Accept: "application/json" },
				signal: controller.signal
			});
			clearTimeout(timeout);
			if (!resp.ok) return null;
			const data = await resp.json();
			if (!data.transaction?.to || !data.transaction?.data) return null;
			if (!isKnownSwapTarget(data.transaction.to)) {
				console.info(`[delegation] Swap API returned unknown target: ${data.transaction.to}`);
				return null;
			}
			return {
				target: data.transaction.to,
				value: BigInt(data.transaction.value || "0"),
				callData: data.transaction.data
			};
		} catch {
			return null;
		}
	},
	bridge: async (args, ctx) => {
		if (args.action !== "execute") return null;
		if (!ctx?.walletAddress) return null;
		const fromChain = args.from_chain;
		const toChain = args.to_chain;
		const amount = args.amount;
		if (!toChain || !amount) return null;
		const fromToken = args.from_token ?? "0x0000000000000000000000000000000000000000";
		const toToken = args.to_token ?? "0x0000000000000000000000000000000000000000";
		const slippage = args.slippage ?? .005;
		const fromChainId = resolveChainId(fromChain ?? "base") ?? ctx.chainId ?? 8453;
		const toChainId = resolveChainId(toChain);
		if (!toChainId) return null;
		try {
			const params = new URLSearchParams({
				fromChain: String(fromChainId),
				toChain: String(toChainId),
				fromToken,
				toToken,
				fromAmount: amount,
				fromAddress: ctx.walletAddress,
				slippage: String(slippage)
			});
			const headers = { Accept: "application/json" };
			const apiKey = process.env.LIFI_API_KEY;
			if (apiKey) headers["x-lifi-api-key"] = apiKey;
			const controller = new AbortController();
			const timeout = setTimeout(() => controller.abort(), 5e3);
			const resp = await fetch(`https://li.quest/v1/quote?${params}`, {
				headers,
				signal: controller.signal
			});
			clearTimeout(timeout);
			if (!resp.ok) return null;
			const txReq = (await resp.json()).transactionRequest;
			if (!txReq?.to || !txReq?.data) return null;
			if (!isKnownBridgeTarget(txReq.to)) {
				console.info(`[delegation] Bridge API returned unknown target: ${txReq.to}`);
				return null;
			}
			return {
				target: txReq.to,
				value: txReq.value ? BigInt(txReq.value) : 0n,
				callData: txReq.data
			};
		} catch {
			return null;
		}
	}
};
const NATIVE_TOKEN_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
/** Resolve token symbol or address for swap API. */
function resolveSwapToken(token) {
	if (/^0x[0-9a-fA-F]{40}$/.test(token)) return token;
	return {
		eth: NATIVE_TOKEN_ADDRESS,
		weth: "0x4200000000000000000000000000000000000006",
		usdc: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
		usdt: "0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2",
		dai: "0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb",
		cbeth: "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22"
	}[token.toLowerCase()] ?? null;
}
/** Resolve chain name to chain ID. */
function resolveChainId(chain) {
	const n = parseInt(chain, 10);
	if (!isNaN(n)) return n;
	return {
		ethereum: 1,
		eth: 1,
		mainnet: 1,
		base: 8453,
		arbitrum: 42161,
		arb: 42161,
		optimism: 10,
		op: 10,
		polygon: 137,
		matic: 137,
		avalanche: 43114,
		avax: 43114,
		bnb: 56,
		bsc: 56,
		linea: 59144,
		zksync: 324,
		scroll: 534352
	}[chain.toLowerCase()] ?? null;
}
/**
* Attempt to execute a tool action via delegation redemption.
*
* Called from the policy gate AFTER policies have been evaluated as 'allow'.
* Returns { executed: true } if the action was successfully redeemed on-chain,
* or { executed: false, skipReason } if delegation was not applicable.
*
* The caller should fall back to normal tool execution when executed === false.
*/
async function tryDelegationExecution(actionCtx, toolArgs) {
	if (!isDelegationMode()) return {
		executed: false,
		skipReason: "Not in delegation mode."
	};
	const extractor = SUPPORTED_EXTRACTORS[actionCtx.toolName];
	if (!extractor) return {
		executed: false,
		skipReason: `Tool "${actionCtx.toolName}" does not support delegation execution yet.`
	};
	const { getWalletState } = await import("./walletconnect-service.mjs");
	const walletState = getWalletState();
	const executionAction = await extractor(toolArgs, {
		walletAddress: walletState.address,
		chainId: walletState.chainId ?? actionCtx.chain
	});
	if (!executionAction) return {
		executed: false,
		skipReason: "Could not extract execution action from tool args."
	};
	try {
		const { hasAdvancedPermissions, getPermissionContext } = await import("./advanced-permissions.mjs");
		const { getWalletClient } = await import("./walletconnect-service.mjs");
		const policies = getDelegatedPolicies(actionCtx.userId);
		for (const p of policies) {
			if (!p.delegation || !hasAdvancedPermissions(p.id)) continue;
			if (!policyScopeCovers(p, actionCtx.toolName)) continue;
			const permCtx = getPermissionContext(p.id);
			if (!permCtx) continue;
			const wc = getWalletClient();
			if (!wc) continue;
			try {
				const { DelegationManager: DM } = await import("@metamask/smart-accounts-kit/contracts");
				const { createExecution, ExecutionMode } = await import("@metamask/smart-accounts-kit");
				const execution = createExecution({
					target: executionAction.target,
					value: executionAction.value,
					callData: executionAction.callData
				});
				const redeemCalldata = DM.encode.redeemDelegations({
					delegations: [[]],
					modes: [ExecutionMode.SingleDefault],
					executions: [[execution]]
				});
				return {
					executed: true,
					txHash: await wc.sendTransaction({
						to: permCtx.delegationManager,
						data: redeemCalldata
					}),
					chainId: p.delegation.chainId
				};
			} catch (apErr) {
				const msg = apErr instanceof Error ? apErr.message : String(apErr);
				console.info(`[delegation] Advanced Permissions failed for ${p.name}: ${msg.slice(0, 100)}`);
			}
		}
	} catch {}
	const matchResult = findMatchingDelegation(actionCtx);
	if (!matchResult) return {
		executed: false,
		skipReason: "No matching delegation found for this action."
	};
	if (matchResult.delegator && executionAction.callData.length > 10) {
		const zeroAddr = "0".repeat(64);
		const delegatorPadded = matchResult.delegator.slice(2).toLowerCase().padStart(64, "0");
		if (executionAction.callData.includes(zeroAddr)) executionAction.callData = executionAction.callData.replaceAll(zeroAddr, delegatorPadded);
	}
	const readiness = canRedeem(matchResult.policyId);
	if (!readiness.ready) return {
		executed: false,
		skipReason: readiness.reason ?? "Delegation not ready."
	};
	if (matchResult.expiresAt) {
		const expiryMs = new Date(matchResult.expiresAt).getTime();
		if (!isNaN(expiryMs) && Date.now() > expiryMs) return {
			executed: false,
			skipReason: "Delegation has expired. Create a new one with /delegate create."
		};
	}
	if (actionCtx.chain && matchResult.chainId && actionCtx.chain !== matchResult.chainId) return {
		executed: false,
		skipReason: `Delegation is for chain ${matchResult.chainId} but wallet is on chain ${actionCtx.chain}. Switch chains or create a new delegation.`
	};
	if (matchResult.delegator) try {
		const { getPublicClient } = await import("./walletconnect-service.mjs");
		const pub = getPublicClient();
		if (pub) {
			const code = await pub.getCode({ address: matchResult.delegator });
			if (!code || code === "0x" || code === "0x0") return {
				executed: false,
				skipReason: `Delegator ${matchResult.delegator} is a plain EOA. On-chain delegation requires a smart account. Use /upgrade to convert.`
			};
		}
	} catch {}
	if (isRateLimited(actionCtx.userId, actionCtx.toolName)) return {
		executed: false,
		skipReason: `Delegation rate-limited for ${actionCtx.toolName} (too many recent attempts). Wait before retrying.`
	};
	recordRedemptionAttempt(actionCtx.userId, actionCtx.toolName);
	try {
		const result = await redeemDelegation(matchResult.policyId, executionAction);
		if ("error" in result) return {
			executed: false,
			error: result.error
		};
		clearRateLimit(actionCtx.userId, actionCtx.toolName);
		return {
			executed: true,
			txHash: result.txHash,
			chainId: result.chainId
		};
	} catch (err) {
		return {
			executed: false,
			error: `Delegation execution error: ${err instanceof Error ? err.message : String(err)}`
		};
	}
}
/**
* Find a delegation that covers the given action.
*
* Matching logic:
* 1. Get all delegated policies for the user
* 2. Filter to active/signed status (not revoked/expired)
* 3. Check if the policy's scope covers the tool
* 4. Return the first match (most recently updated)
*
* Future: rank by remaining budget, prefer policies with more headroom.
*/
function findMatchingDelegation(ctx) {
	const policies = getDelegatedPolicies(ctx.userId);
	for (const policy of policies) {
		const info = policy.delegation;
		if (!info) continue;
		if (info.status !== "signed" && info.status !== "active") continue;
		if (!policyScopeCovers(policy, ctx.toolName)) continue;
		return {
			policyId: policy.id,
			policyName: policy.name,
			chainId: info.chainId,
			delegator: info.delegator,
			expiresAt: info.expiresAt
		};
	}
	return null;
}
/**
* Check if a policy's scope covers a specific tool.
* Mirrors policyApplies() in policy-evaluator.ts.
*/
function policyScopeCovers(policy, toolName) {
	const { scope } = policy;
	if (scope.type === "all_write") return true;
	if (scope.type === "tools") return (scope.tools ?? []).includes(toolName);
	if (scope.type === "categories") {
		const TOOL_CATEGORIES = {
			defi: [
				"defi_swap",
				"defi_lend",
				"defi_stake",
				"liquidity",
				"yield",
				"bridge",
				"permit2",
				"approvals",
				"wayfinder",
				"molten"
			],
			transfer: ["transfer"],
			fiat: ["fiat_payment"],
			bankr: [
				"bankr_launch",
				"bankr_automate",
				"bankr_polymarket",
				"bankr_leverage"
			],
			social: ["clawnx", "farcaster"],
			nft: ["nft", "airdrop"],
			governance: ["governance", "safe"],
			platform: [
				"clawnch_launch",
				"clawnch_fees",
				"clawnch_info",
				"hummingbot"
			],
			orchestration: [
				"manage_orders",
				"compound_action",
				"crypto_workflow"
			],
			privacy: ["privacy"],
			browser: ["browser"],
			wallet: ["clawnchconnect"]
		};
		let toolCategory;
		for (const [cat, tools] of Object.entries(TOOL_CATEGORIES)) if (tools.includes(toolName)) {
			toolCategory = cat;
			break;
		}
		if (!toolCategory) return false;
		return (scope.categories ?? []).includes(toolCategory);
	}
	return false;
}
/**
* Check if delegation execution is available for a tool.
* Quick sync check — verifies the tool has an extractor and a matching
* delegation exists. Does NOT verify the extractor can parse the specific
* args (that's async and happens in tryDelegationExecution).
*/
function isDelegationExecutionAvailable(toolName, userId) {
	if (!isDelegationMode()) return false;
	if (!SUPPORTED_EXTRACTORS[toolName]) return false;
	return getDelegatedPolicies(userId).some((p) => {
		const info = p.delegation;
		if (!info) return false;
		if (info.status !== "signed" && info.status !== "active") return false;
		return policyScopeCovers(p, toolName);
	});
}
/**
* Get the list of tools that support delegation execution.
*/
function getDelegationSupportedTools() {
	return Object.keys(SUPPORTED_EXTRACTORS);
}
//#endregion
export { clearRateLimit, getDelegationSupportedTools, isDelegationExecutionAvailable, tryDelegationExecution };

//# sourceMappingURL=delegation-executor.mjs.map