import { RevokeType as e } from "../../types/approvals.types.mjs";
import { ALCHEMY_API_KEY as t, chainIds as n } from "../../constants/chains.constants.mjs";
import { zeroAddress as r } from "../../constants/protocol.constants.mjs";
import { StorageKeys as i } from "../../types/cache.types.mjs";
import { httpClient as a } from "../http/HttpClient.mjs";
import { caseInsensitiveEqual as o } from "../../functions/utils/caseInsensitive.utils.mjs";
import { API as s } from "../../API/API.mjs";
import { isNFTToken as c } from "../../functions/utils/erc20tokenFunctions.mjs";
import { EVENTS_INITIAL_BLOCKS as l } from "../../constants/events.constants.mjs";
import { Logger as u } from "../../error-handling/logger.mjs";
import { getStateKey as d } from "../../functions/utils/string.utils.mjs";
import { createJsonRpcProvider as f } from "../../functions/utils/create-provider.mjs";
import { Mutex as p } from "async-mutex";
import { ethers as m } from "ethers";
import { get as h, update as g } from "idb-keyval";
//#region libs/shared/common/src/data-structures/ApprovalDBs/EventsPublicApprovalsDB.ts
var _ = class {
	updateMutexes = {};
	approvalTopic = m.id("Approval(address,address,uint256)");
	approvalForAllTopic = m.id("ApprovalForAll(address,address,bool)");
	getApprovedSelector = m.id("getApproved(uint256)").substring(0, 10);
	isApprovedForAllSelector = m.id("isApprovedForAll(address,address)").substring(0, 10);
	ALCHEMY_URLS = {
		[n.ethMainnet]: "eth-mainnet",
		[n.polygon]: "polygon-mainnet",
		[n.arbMainnet]: "arb-mainnet",
		[n.optimism]: "opt-mainnet",
		[n.base]: "base-mainnet",
		[n.arcTestnet]: "arc-testnet"
	};
	getMutex(e) {
		return this.updateMutexes[e] || (this.updateMutexes[e] = new p()), this.updateMutexes[e];
	}
	getAlchemyUrl(e) {
		let n = this.ALCHEMY_URLS[e];
		if (!n) throw Error(`Unsupported chainId for Alchemy: ${e}`);
		return `https://${n}.g.alchemy.com/v2/${t}`;
	}
	async getApprovals(e, t) {
		let n = d(t, e);
		return (await h(i.EVENTS_PUBLIC_APPROVALS))?.[n] || [];
	}
	async getLastProcessedBlock(e, t) {
		return (await h(i.PUBLIC_APPROVALS_LAST_PROCESSED_BLOCKS) || {})[d(t, e)] || l[e];
	}
	async updateLastProcessedBlock(e, t, n) {
		await g(i.PUBLIC_APPROVALS_LAST_PROCESSED_BLOCKS, (r = {}) => {
			let i = d(t, e);
			return {
				...r,
				[i]: n
			};
		});
	}
	async getApprovalEvents(e, t) {
		try {
			let n = f(t), r = await this.getLastProcessedBlock(t, e) + 1, i = await n.getBlockNumber();
			if (r > i) return {
				approvalEvents: [],
				latestBlock: i
			};
			let a = m.zeroPadValue(e.toLowerCase(), 32), o = {
				topics: [[this.approvalTopic, this.approvalForAllTopic], a],
				fromBlock: r,
				toBlock: i
			};
			return {
				approvalEvents: await n.getLogs(o),
				latestBlock: i
			};
		} catch (e) {
			return u.error("Failed to fetch approval events", e), {
				approvalEvents: [],
				latestBlock: void 0
			};
		}
	}
	async checkCurrentAllowances(t, n, i) {
		let l = this.getAlchemyUrl(t), d = `0x${n.substring(2).padStart(64, "0")}`, f = [...new Set(i.map((e) => e.contractAddress))], p = (await s.tokensInfoCall(t, f)).filter((e) => !!e), m = new Map(p.map((e) => [e.erc20TokenAddress.toLowerCase(), e])), h = [], g = [];
		if (i.forEach((t, r) => {
			let i = m.get(t.contractAddress.toLowerCase());
			if (i) if (!c(i)) h.push({
				jsonrpc: "2.0",
				id: h.length,
				method: "alchemy_getTokenAllowance",
				params: [{
					contract: t.contractAddress,
					owner: n,
					spender: t.spenderAddress
				}]
			}), g.push({
				pairIndex: r,
				type: e.ERC20
			});
			else {
				let n = `0x${t.spenderAddress.substring(2).padStart(64, "0")}`, i = `${this.isApprovedForAllSelector}${d.substring(2)}${n.substring(2)}`;
				h.push({
					jsonrpc: "2.0",
					id: h.length,
					method: "eth_call",
					params: [{
						to: t.contractAddress,
						data: i
					}, "latest"]
				}), g.push({
					pairIndex: r,
					type: e.approvedForAll
				}), t.tokenIds && t.tokenIds.size > 0 && t.tokenIds.forEach((n) => {
					let i = BigInt(n).toString(16).padStart(64, "0"), a = `${this.getApprovedSelector}${i}`;
					h.push({
						jsonrpc: "2.0",
						id: h.length,
						method: "eth_call",
						params: [{
							to: t.contractAddress,
							data: a
						}, "latest"]
					}), g.push({
						pairIndex: r,
						type: e.tokenId,
						tokenId: n
					});
				});
			}
		}), h.length === 0) return [];
		let _ = await a.post(l, h), v = [], y = /* @__PURE__ */ new Set();
		return _.forEach((t, n) => {
			let a = g[n];
			if (!a) return;
			let s = i[a.pairIndex], c = m.get(s.contractAddress.toLowerCase());
			if (!(!c || o(s.spenderAddress, r)) && !t?.error && t?.result && t.result !== "0x") try {
				if (a.type === e.ERC20 && BigInt(t.result) > 0n) v.push({
					token: c,
					spenderAddress: s.spenderAddress,
					allowance: BigInt(t.result)
				});
				else if (a.type === e.approvedForAll && BigInt(t.result) === 1n) y.add(a.pairIndex), v.push({
					token: c,
					spenderAddress: s.spenderAddress,
					allowance: 1n
				});
				else if (a.type === e.tokenId && !y.has(a.pairIndex)) {
					let e = `0x${t.result.substring(26)}`.toLowerCase();
					!o(e, r) && o(e, s.spenderAddress) && v.push({
						token: c,
						spenderAddress: s.spenderAddress,
						allowance: 1n,
						tokenId: a.tokenId
					});
				}
			} catch (e) {
				u.error("Error processing approval response", e);
			}
		}), v;
	}
	async fetchAndUpdatePublicApprovals(e, t) {
		let n = d(e, t);
		await this.getMutex(n).runExclusive(async () => {
			try {
				let { approvalEvents: a, latestBlock: s } = await this.getApprovalEvents(e, t);
				if (!s) return;
				let c = await this.getApprovals(t, e), l = /* @__PURE__ */ new Map();
				if (c.forEach((e) => {
					let t = e.token.erc20TokenAddress.toLowerCase(), n = e.spenderAddress.toLowerCase(), r = `${t}_${n}`, i = l.get(r);
					i || (i = {
						contractAddress: t,
						spenderAddress: n,
						tokenIds: /* @__PURE__ */ new Set()
					}, l.set(r, i)), e.tokenId && i.tokenIds && i.tokenIds.add(e.tokenId);
				}), a.forEach((e) => {
					if (!e.topics[2]) return;
					let t = e.address.toLowerCase(), n = `0x${e.topics[2].substring(26)}`.toLowerCase();
					if (o(n, r)) return;
					let i = `${t}_${n}`, a = l.get(i);
					if (a || (a = {
						contractAddress: t,
						spenderAddress: n,
						tokenIds: /* @__PURE__ */ new Set()
					}, l.set(i, a)), e.topics.length === 4 && a.tokenIds) {
						let t = BigInt(e.topics[3]).toString();
						a.tokenIds.add(t);
					}
				}), l.size === 0) {
					await this.updateLastProcessedBlock(t, e, s);
					return;
				}
				let u = Array.from(l.values()), d = await this.checkCurrentAllowances(t, e, u);
				await g(i.EVENTS_PUBLIC_APPROVALS, (e = {}) => ({
					...e,
					[n]: d
				})), await this.updateLastProcessedBlock(t, e, s);
			} catch (e) {
				u.error("Failed to sync approvals", e);
			}
		});
	}
}, v = new _();
//#endregion
export { _ as EventsPublicApprovalsDB, v as eventsPublicApprovalsDB };
