import { guardedFetch } from "./endpoint-allowlist.mjs";
import { a as parseEther } from "../../_esm-BrzUp3yp.mjs";
import { M as formatUnits } from "../../chain-dTUyiOxD.mjs";
import { CBETH, LIDO, ROCKET_POOL } from "../lib/contract-registry.mjs";
//#region extensions/crypto/src/services/staking-service.ts
/**
* Staking Service — liquid staking protocol integrations.
*
* Supports:
*   - Lido (stETH / wstETH) on Ethereum mainnet
*   - Coinbase (cbETH) on Ethereum mainnet
*   - Rocket Pool (rETH) on Ethereum mainnet
*
* Uses same ABI-call pattern as lending-service.ts. All protocols
* are simple contract calls — no external SDK dependencies.
*
* APY data fetched from DeFiLlama yields API.
*/
const CONTRACTS = {
	lido: {
		stETH: LIDO.ethereum.stETH,
		wstETH: LIDO.ethereum.wstETH
	},
	rocketPool: {
		rETH: ROCKET_POOL.ethereum.rETH,
		depositPool: ROCKET_POOL.ethereum.depositPool
	},
	cbETH: CBETH.ethereum
};
const BASE_TOKENS = {
	wstETH: LIDO.base.wstETH,
	cbETH: CBETH.base,
	rETH: ROCKET_POOL.base.rETH
};
const LIDO_STETH_ABI = [
	{
		name: "submit",
		inputs: [{
			name: "_referral",
			type: "address"
		}],
		outputs: [{
			name: "",
			type: "uint256"
		}],
		stateMutability: "payable",
		type: "function"
	},
	{
		name: "balanceOf",
		inputs: [{
			name: "_account",
			type: "address"
		}],
		outputs: [{
			name: "",
			type: "uint256"
		}],
		stateMutability: "view",
		type: "function"
	},
	{
		name: "approve",
		inputs: [{
			name: "_spender",
			type: "address"
		}, {
			name: "_amount",
			type: "uint256"
		}],
		outputs: [{
			name: "",
			type: "bool"
		}],
		stateMutability: "nonpayable",
		type: "function"
	},
	{
		name: "allowance",
		inputs: [{
			name: "_owner",
			type: "address"
		}, {
			name: "_spender",
			type: "address"
		}],
		outputs: [{
			name: "",
			type: "uint256"
		}],
		stateMutability: "view",
		type: "function"
	}
];
const WSTETH_ABI = [
	{
		name: "wrap",
		inputs: [{
			name: "_stETHAmount",
			type: "uint256"
		}],
		outputs: [{
			name: "",
			type: "uint256"
		}],
		stateMutability: "nonpayable",
		type: "function"
	},
	{
		name: "unwrap",
		inputs: [{
			name: "_wstETHAmount",
			type: "uint256"
		}],
		outputs: [{
			name: "",
			type: "uint256"
		}],
		stateMutability: "nonpayable",
		type: "function"
	},
	{
		name: "balanceOf",
		inputs: [{
			name: "_account",
			type: "address"
		}],
		outputs: [{
			name: "",
			type: "uint256"
		}],
		stateMutability: "view",
		type: "function"
	},
	{
		name: "stEthPerToken",
		inputs: [],
		outputs: [{
			name: "",
			type: "uint256"
		}],
		stateMutability: "view",
		type: "function"
	},
	{
		name: "tokensPerStEth",
		inputs: [],
		outputs: [{
			name: "",
			type: "uint256"
		}],
		stateMutability: "view",
		type: "function"
	}
];
const ROCKET_DEPOSIT_ABI = [{
	name: "deposit",
	inputs: [],
	outputs: [],
	stateMutability: "payable",
	type: "function"
}];
const RETH_ABI = [
	{
		name: "burn",
		inputs: [{
			name: "_rethAmount",
			type: "uint256"
		}],
		outputs: [],
		stateMutability: "nonpayable",
		type: "function"
	},
	{
		name: "balanceOf",
		inputs: [{
			name: "_account",
			type: "address"
		}],
		outputs: [{
			name: "",
			type: "uint256"
		}],
		stateMutability: "view",
		type: "function"
	},
	{
		name: "getExchangeRate",
		inputs: [],
		outputs: [{
			name: "",
			type: "uint256"
		}],
		stateMutability: "view",
		type: "function"
	}
];
const ERC20_BALANCE_ABI = [{
	name: "balanceOf",
	inputs: [{
		name: "account",
		type: "address"
	}],
	outputs: [{
		name: "",
		type: "uint256"
	}],
	stateMutability: "view",
	type: "function"
}];
var StakingService = class {
	apyCache = [];
	apyCacheTimestamp = 0;
	APY_CACHE_TTL = 6e5;
	getSupportedProtocols() {
		return [
			{
				id: "lido",
				name: "Lido",
				assets: ["stETH", "wstETH"],
				chain: "ethereum"
			},
			{
				id: "rocket_pool",
				name: "Rocket Pool",
				assets: ["rETH"],
				chain: "ethereum"
			},
			{
				id: "coinbase",
				name: "Coinbase",
				assets: ["cbETH"],
				chain: "ethereum"
			}
		];
	}
	resolveProtocol(input) {
		const lower = input.toLowerCase();
		if (lower === "lido" || lower === "steth" || lower === "wsteth") return "lido";
		if (lower === "rocket_pool" || lower === "rocketpool" || lower === "reth") return "rocket_pool";
		if (lower === "coinbase" || lower === "cbeth" || lower === "cb") return "coinbase";
		return null;
	}
	async stakeEth(protocol, amount, userAddress, walletClient, publicClient) {
		switch (protocol) {
			case "lido": return this.stakeLido(amount, userAddress, walletClient, publicClient);
			case "rocket_pool": return this.stakeRocketPool(amount, walletClient, publicClient);
			case "coinbase": throw new Error("cbETH cannot be minted directly. Swap ETH for cbETH using defi_swap tool instead.");
			default: throw new Error(`Unknown protocol: ${protocol}`);
		}
	}
	async stakeLido(amount, _userAddress, walletClient, publicClient) {
		const hash = await walletClient.writeContract({
			address: CONTRACTS.lido.stETH,
			abi: LIDO_STETH_ABI,
			functionName: "submit",
			args: ["0x0000000000000000000000000000000000000000"],
			value: amount
		});
		await publicClient.waitForTransactionReceipt({ hash });
		return {
			hash,
			protocol: "lido",
			action: "stake",
			asset: "stETH",
			amount: formatUnits(amount, 18)
		};
	}
	async stakeRocketPool(amount, walletClient, publicClient) {
		const hash = await walletClient.writeContract({
			address: CONTRACTS.rocketPool.depositPool,
			abi: ROCKET_DEPOSIT_ABI,
			functionName: "deposit",
			args: [],
			value: amount
		});
		await publicClient.waitForTransactionReceipt({ hash });
		return {
			hash,
			protocol: "rocket_pool",
			action: "stake",
			asset: "rETH",
			amount: formatUnits(amount, 18)
		};
	}
	async unstake(protocol, amount, _userAddress, walletClient, publicClient) {
		switch (protocol) {
			case "rocket_pool": return this.unstakeRocketPool(amount, walletClient, publicClient);
			case "lido": throw new Error("Lido unstaking uses a withdrawal queue (7+ days). For instant exit, swap stETH/wstETH for ETH using defi_swap tool.");
			case "coinbase": throw new Error("cbETH cannot be redeemed directly. Swap cbETH for ETH using defi_swap tool.");
			default: throw new Error(`Unknown protocol: ${protocol}`);
		}
	}
	async unstakeRocketPool(amount, walletClient, publicClient) {
		const hash = await walletClient.writeContract({
			address: CONTRACTS.rocketPool.rETH,
			abi: RETH_ABI,
			functionName: "burn",
			args: [amount]
		});
		await publicClient.waitForTransactionReceipt({ hash });
		return {
			hash,
			protocol: "rocket_pool",
			action: "unstake",
			asset: "rETH",
			amount: formatUnits(amount, 18)
		};
	}
	async wrap(amount, userAddress, walletClient, publicClient) {
		await this.ensureStEthApproval(amount, userAddress, walletClient, publicClient);
		const hash = await walletClient.writeContract({
			address: CONTRACTS.lido.wstETH,
			abi: WSTETH_ABI,
			functionName: "wrap",
			args: [amount]
		});
		await publicClient.waitForTransactionReceipt({ hash });
		return {
			hash,
			protocol: "lido",
			action: "wrap",
			asset: "wstETH",
			amount: formatUnits(amount, 18)
		};
	}
	async unwrap(amount, _userAddress, walletClient, publicClient) {
		const hash = await walletClient.writeContract({
			address: CONTRACTS.lido.wstETH,
			abi: WSTETH_ABI,
			functionName: "unwrap",
			args: [amount]
		});
		await publicClient.waitForTransactionReceipt({ hash });
		return {
			hash,
			protocol: "lido",
			action: "unwrap",
			asset: "stETH",
			amount: formatUnits(amount, 18)
		};
	}
	async ensureStEthApproval(amount, userAddress, walletClient, publicClient) {
		if (await publicClient.readContract({
			address: CONTRACTS.lido.stETH,
			abi: LIDO_STETH_ABI,
			functionName: "allowance",
			args: [userAddress, CONTRACTS.lido.wstETH]
		}) < amount) {
			const approvalAmount = amount + amount / 200n;
			const approveHash = await walletClient.writeContract({
				address: CONTRACTS.lido.stETH,
				abi: LIDO_STETH_ABI,
				functionName: "approve",
				args: [CONTRACTS.lido.wstETH, approvalAmount]
			});
			await publicClient.waitForTransactionReceipt({ hash: approveHash });
		}
	}
	async getPositions(userAddress, chainId, publicClient) {
		const positions = [];
		if (chainId === 1) {
			const checks = [
				this.checkBalance(publicClient, CONTRACTS.lido.stETH, LIDO_STETH_ABI, userAddress, "Lido", "stETH"),
				this.checkBalance(publicClient, CONTRACTS.lido.wstETH, WSTETH_ABI, userAddress, "Lido", "wstETH"),
				this.checkBalance(publicClient, CONTRACTS.rocketPool.rETH, RETH_ABI, userAddress, "Rocket Pool", "rETH"),
				this.checkBalance(publicClient, CONTRACTS.cbETH, ERC20_BALANCE_ABI, userAddress, "Coinbase", "cbETH")
			];
			const results = await Promise.allSettled(checks);
			for (const r of results) if (r.status === "fulfilled" && r.value) positions.push({
				...r.value,
				chain: "ethereum"
			});
			await this.enrichWithExchangeRates(positions, publicClient, 1);
		} else if (chainId === 8453) {
			const checks = [
				this.checkBalance(publicClient, BASE_TOKENS.wstETH, ERC20_BALANCE_ABI, userAddress, "Lido", "wstETH"),
				this.checkBalance(publicClient, BASE_TOKENS.cbETH, ERC20_BALANCE_ABI, userAddress, "Coinbase", "cbETH"),
				this.checkBalance(publicClient, BASE_TOKENS.rETH, ERC20_BALANCE_ABI, userAddress, "Rocket Pool", "rETH")
			];
			const results = await Promise.allSettled(checks);
			for (const r of results) if (r.status === "fulfilled" && r.value) positions.push({
				...r.value,
				chain: "base"
			});
		}
		await this.enrichWithApy(positions);
		return positions;
	}
	async checkBalance(publicClient, tokenAddress, abi, userAddress, protocol, asset) {
		try {
			const balance = await publicClient.readContract({
				address: tokenAddress,
				abi,
				functionName: "balanceOf",
				args: [userAddress]
			});
			if (balance === 0n) return null;
			return {
				protocol,
				asset,
				balance: formatUnits(balance, 18),
				balanceEth: formatUnits(balance, 18)
			};
		} catch {
			return null;
		}
	}
	async enrichWithExchangeRates(positions, publicClient, chainId) {
		if (chainId !== 1) return;
		for (const pos of positions) try {
			if (pos.asset === "wstETH") {
				const stEthPerToken = await publicClient.readContract({
					address: CONTRACTS.lido.wstETH,
					abi: WSTETH_ABI,
					functionName: "stEthPerToken"
				});
				pos.balanceEth = formatUnits(parseEther(pos.balance) * stEthPerToken / BigInt(0xde0b6b3a7640000), 18);
			} else if (pos.asset === "rETH") {
				const exchangeRate = await publicClient.readContract({
					address: CONTRACTS.rocketPool.rETH,
					abi: RETH_ABI,
					functionName: "getExchangeRate"
				});
				pos.balanceEth = formatUnits(parseEther(pos.balance) * exchangeRate / BigInt(0xde0b6b3a7640000), 18);
			}
		} catch {}
	}
	async getApys() {
		if (this.apyCache.length > 0 && Date.now() - this.apyCacheTimestamp < this.APY_CACHE_TTL) return this.apyCache;
		try {
			const response = await guardedFetch("https://yields.llama.fi/pools", {
				headers: { Accept: "application/json" },
				signal: AbortSignal.timeout(1e4)
			});
			if (!response.ok) return this.apyCache;
			this.apyCache = ((await response.json()).data ?? []).filter((p) => (p.project === "lido" || p.project === "rocket-pool" || p.project === "coinbase-wrapped-staked-eth") && p.chain === "Ethereum" && (p.symbol?.includes("ETH") || p.symbol?.includes("stETH"))).map((p) => ({
				protocol: p.project,
				symbol: p.symbol,
				apy: p.apy ?? p.apyBase ?? 0,
				tvl: p.tvlUsd ?? 0,
				fetchedAt: Date.now()
			}));
			this.apyCacheTimestamp = Date.now();
			return this.apyCache;
		} catch {
			return this.apyCache;
		}
	}
	async enrichWithApy(positions) {
		const apys = await this.getApys();
		for (const pos of positions) {
			const match = apys.find((a) => {
				if (pos.protocol === "Lido") return a.protocol === "lido";
				if (pos.protocol === "Rocket Pool") return a.protocol === "rocket-pool";
				if (pos.protocol === "Coinbase") return a.protocol === "coinbase-wrapped-staked-eth";
				return false;
			});
			if (match) pos.apy = `${match.apy.toFixed(2)}%`;
		}
	}
};
let _instance = null;
function getStakingService() {
	if (!_instance) _instance = new StakingService();
	return _instance;
}
function resetStakingService() {
	_instance = null;
}
//#endregion
export { StakingService, getStakingService, resetStakingService };

//# sourceMappingURL=staking-service.mjs.map