import { CustomJSONStringify as e } from "../../functions/utils/serialize.utils.mjs";
import { isExtension as t } from "../../constants/vite.constants.mjs";
import { HINKAL_SUPPORTED_CHAINS as n, WALLET_SUPPORTED_CHAINS as r, chainIds as i, currentTronChainId as a, isSolanaLike as o, isTronLike as s, networkRegistry as c } from "../../constants/chains.constants.mjs";
import { EventType as l, LoginMessageMode as u } from "../../types/hinkal.types.mjs";
import { ContractType as d } from "../../types/ethereum-network.types.mjs";
import { poseidonFunction as f } from "../../crypto/poseidon.mjs";
import { getAccessTokenMerkleAccountPublicKey as p, getMerkleAccountPublicKey as m } from "../../functions/pre-transaction/solana.mjs";
import { hinkalCheckSolanaTokenRegistry as ee } from "./hinkalCheckSolanaTokenRegistry.mjs";
import { checkHinkalAccessToken as te } from "../../functions/web3/functionCalls/accessTokenCalls.mjs";
import { transactionErrorCodes as h } from "../../error-handling/error-codes.constants.mjs";
import { getErc20TokensForChain as g } from "../../functions/utils/erc20tokenFunctions.mjs";
import { UserKeys as _ } from "../crypto-keys/keys.mjs";
import { API as v } from "../../API/API.mjs";
import { validateAndGetChainId as y } from "../../functions/utils/token-check.utils.mjs";
import { privateTokensDB as ne } from "../TokenDBs/PrivateTokensDB.mjs";
import { getShieldedBalance as re } from "../../functions/web3/events/getShieldedBalance.mjs";
import { supportedPassportLinks as b } from "../../constants/kyc.constants.mjs";
import { reloadPage as x } from "../../functions/utils/reloadPage.mjs";
import { createCacheDevice as S } from "../../functions/utils/cacheDevice.utils.mjs";
import { getContractWithFetcherByChainId as C } from "../../functions/web3/getContractMetadata.mjs";
import { SolanaProviderAdapter as w } from "../../providers/SolanaProviderAdapter.mjs";
import { hinkalCheckTokenRegistry as T, hinkalCheckTronTokenRegistry as E } from "./hinkalCheckTokenRegistry.mjs";
import { MerkleTree as D } from "../merkle-tree/MerkleTree.mjs";
import "../merkle-tree/index.mjs";
import { fetchSolanaMerkleTreeRootHash as O } from "../../functions/web3/fetchSolanaMerkleTreeRootHash.mjs";
import { hinkalDeposit as k, hinkalDepositForOther as A } from "./hinkalDeposit.mjs";
import { createTransaferEmporiumOpsBatch as j } from "../../functions/private-wallet/emporium.helpers.mjs";
import "../../API/index.mjs";
import { checkTokenLimitsUSD as M } from "../../functions/kyc/checkTokenLimitsUSD.mjs";
import { hinkalDepositAndWithdraw as N } from "./hinkalDepositAndWithdraw.mjs";
import { hinkalSolanaDeposit as P, hinkalSolanaDepositForOther as F } from "./hinkalSolanaDeposit.mjs";
import { hinkalSwap as I } from "./hinkalSwap.mjs";
import { hinkalWithdraw as L } from "./hinkalWithdraw.mjs";
import { resetMerkleTrees as R } from "./resetMerkleTrees.mjs";
import { MultiThreadedUtxoUtils as z } from "../MultiThreadedUtxoUtils/MultiThreadedUtxoUtils.mjs";
import { hinkalPrivateWallet as ie } from "./hinkalPrivateWallet.mjs";
import { getRecipientInfo as B } from "./hinkalGetRecipientInfo.mjs";
import { hinkalSignSubAccount as V } from "./hinkalSignSubAccount.mjs";
import { hinkalActionReceive as H } from "./hinkalActionReceive.mjs";
import "../TokenDBs/index.mjs";
import { hinkalProoflessDeposit as U } from "./hinkalProoflessDeposit.mjs";
import { hinkalProxySwap as W } from "./hinkalProxySwap.mjs";
import { hinkalMultiSendPrivateRecipients as G } from "./hinkalMultiSend.mjs";
import { hinkalTransfer as K } from "./hinkalTransfer.mjs";
import { hinkalProxyToPrivate as q } from "./hinkalProxyToPrivate.mjs";
import { TronProviderAdapter as J } from "../../providers/TronProviderAdapter.mjs";
import { hinkalSolanaDepositAndWithdraw as Y } from "./hinkalSolanaDepositAndWithdraw.mjs";
import { hinkalSolanaWithdraw as ae } from "./hinkalSolanaWithdraw.mjs";
import { hinkalSolanaTransfer as oe } from "./hinkalSolanaTransfer.mjs";
import { hinkalSolanaSwap as se } from "./hinkalSolanaSwap.mjs";
import { hinkalSolanaProxySend as ce } from "./hinkalSolanaProxySend.mjs";
import { hinkalSolanaProxySwap as le } from "./hinkalSolanaProxySwap.mjs";
import { hinkalSolanaProxyShield as X } from "./hinkalSolanaProxyShield.mjs";
import { hinkalDepositAndBridge as ue } from "./hinkalDepositAndBridge.mjs";
import { hinkalClaimUtxo as de } from "./hinkalClaimUtxo.mjs";
import { hinkalSolanaProoflessDeposit as Z } from "./hinkalSolanaProoflessDeposit.mjs";
import { hinkalSolanaClaimUtxo as fe } from "./hinkalSolanaClaimUtxo.mjs";
import { hinkalWithdrawStuckUtxos as pe } from "./hinkalWithdrawStuckUtxos.mjs";
import { ethers as Q } from "ethers";
import { PublicKey as $ } from "@solana/web3.js";
//#region libs/shared/common/src/data-structures/Hinkal/Hinkal.ts
var me = class {
	ethereumProviderAdapter;
	solanaProviderAdapter;
	tronProviderAdapter;
	userKeys;
	signingMessage = "Login to Hinkal Protocol";
	privateTransferSigningMessage = "Login to Hinkal's Private Transfer App";
	merkleTreeHinkalByChain = {};
	merkleTreeAccessTokenByChain = {};
	nullifiersByChain = {};
	encryptedOutputsByChain = {};
	commitmentsSnapshotServiceByChain = {};
	nullifierSnapshotServiceByChain = {};
	accessTokenSnapshotServiceByChain = {};
	utxoUtils;
	lastCallState = /* @__PURE__ */ new Map();
	cacheDevice;
	generateProofRemotely;
	disableMerkleTreeUpdates;
	constructor(e) {
		this.userKeys = new _(void 0), n.forEach((e) => {
			this.merkleTreeHinkalByChain[e] = D.create(f, 0n), this.merkleTreeAccessTokenByChain[e] = D.create(f, 0n), this.nullifiersByChain[e] = /* @__PURE__ */ new Set(), this.encryptedOutputsByChain[e] = [];
		}), this.generateProofRemotely = e?.generateProofRemotely ?? !0, this.utxoUtils = new z(), this.cacheDevice = S(e), this.disableMerkleTreeUpdates = e?.disableMerkleTreeUpdates ?? !1;
	}
	enforceRateLimit(t, n, r = 1e3) {
		let i = Date.now(), a = e(n), o = this.lastCallState.get(t);
		if (o && o.argsKey === a && i - o.timestamp < r) throw Error(`${t} was already called with the same arguments`);
		this.lastCallState.set(t, {
			timestamp: i,
			argsKey: a
		});
	}
	getProviderAdapter(e) {
		let t = e;
		t ||= this.ethereumProviderAdapter ? i.ethMainnet : this.solanaProviderAdapter ? i.solanaMainnet : i.tronMainnet;
		let n;
		if (n = o(t) ? this.solanaProviderAdapter : s(t) ? this.tronProviderAdapter : this.ethereumProviderAdapter, !n) throw Error("ProviderAdapter is not initialized");
		return n;
	}
	async initProviderAdapter(e, t) {
		let n = i.ethMainnet;
		t instanceof w ? n = i.solanaMainnet : t instanceof J && (n = a), await this.updateProviderAdapter(n, t), t.initConnector(e);
		let r = await t.connectAndPatchProvider(e);
		await t.init(r), await this.setListeners();
	}
	getSigningMessage(e = u.PROTOCOL) {
		switch (e) {
			case u.PRIVATE_TRANSFER: return this.privateTransferSigningMessage;
			case u.PROTOCOL:
			default: return this.signingMessage;
		}
	}
	async initUserKeys(e = u.PROTOCOL) {
		let t = this.getSigningMessage(e);
		this.userKeys = new _(await this.getProviderAdapter().signMessage(t));
	}
	initUserKeysWithSignature(e) {
		this.userKeys = new _(e);
	}
	async initUserKeysFromSeedPhrases(e) {
		let t = e.join(" "), n = Q.toUtf8Bytes(t), r = Q.keccak256(n);
		this.userKeys = new _(r);
	}
	async resetMerkle(e) {
		this.disableMerkleTreeUpdates || (e?.every((e) => this.isSelectedNetworkSupported(e)) ?? !0) && await R(this, e);
	}
	getTronWeb() {
		let e = this.tronProviderAdapter;
		if (!e) throw Error("Tron provider adapter not initialized");
		if (!(e instanceof J)) throw Error("Tron provider adapter is not a TronProviderAdapter");
		let t = e.getTronWeb();
		if (!t) throw Error("TronWeb not available");
		return t;
	}
	getSupportedChains() {
		return this.ethereumProviderAdapter && this.solanaProviderAdapter ? r : this.ethereumProviderAdapter ? n.filter((e) => !o(e) && !s(e)) : this.solanaProviderAdapter ? n.filter((e) => o(e)) : this.tronProviderAdapter ? n.filter((e) => s(e)) : [];
	}
	async waitForTransaction(e, t, n = 1) {
		return !!await this.getProviderAdapter(e).waitForTransaction(e, t, n);
	}
	getContract(e, t, n = void 0) {
		return this.getProviderAdapter(e).getContract(e, t, n);
	}
	getContractWithFetcherByChainId(e, t, n = void 0) {
		return C(e, t, n);
	}
	async signMessage(e) {
		return await this.getProviderAdapter().signMessage(e);
	}
	async signTypedData(e, t, n) {
		return await this.getProviderAdapter().signTypedData(e, t, n);
	}
	async signWithSubAccount(e, t, n, r) {
		return V(e, t, n, r);
	}
	getContractWithSigner(e, t, n = "") {
		return this.getProviderAdapter(e).getContractWithSigner(e, t, n);
	}
	getContractWithFetcher(e, t, n = "") {
		return this.getProviderAdapter(e).getContractWithFetcher(e, t, n);
	}
	isSelectedNetworkSupported(e) {
		return !!c[e];
	}
	async switchNetwork(e) {
		try {
			await this.getProviderAdapter().switchNetwork(e);
		} catch {
			throw Error(h.FAILED_TO_SWITCH_NETWORKS);
		}
	}
	isPermitterAvailable(e) {
		return this.getProviderAdapter(e).isPermitterAvailable();
	}
	async disconnectFromConnector() {
		await this.ethereumProviderAdapter?.disconnectFromConnector(), await this.solanaProviderAdapter?.disconnectFromConnector(), await this.tronProviderAdapter?.disconnectFromConnector();
	}
	async resetProviderAdapters() {
		this.ethereumProviderAdapter = void 0, this.solanaProviderAdapter = void 0, this.tronProviderAdapter = void 0;
	}
	async updateProviderAdapter(e, t) {
		try {
			o(e) ? (this.solanaProviderAdapter && this.solanaProviderAdapter.release(), this.solanaProviderAdapter = t) : s(e) ? (this.tronProviderAdapter && this.tronProviderAdapter.release(), this.tronProviderAdapter = t) : (this.ethereumProviderAdapter && this.ethereumProviderAdapter.release(), this.ethereumProviderAdapter = t);
		} catch (e) {
			throw console.error(e), Error("updateProviderAdapter failed, please try again.");
		}
	}
	async setListeners() {
		this.ethereumProviderAdapter?.setChainEventListener({
			onAccountChanged: () => {
				this.onAccountChanged();
			},
			onChainChanged: (e) => {
				this.onChainChanged(e);
			}
		}), this.solanaProviderAdapter?.setChainEventListener({
			onAccountChanged: () => {
				this.onAccountChanged();
			},
			onChainChanged: (e) => {
				this.onChainChanged(e);
			}
		}), this.tronProviderAdapter?.setChainEventListener({
			onAccountChanged: () => {
				this.onAccountChanged();
			},
			onChainChanged: (e) => {
				this.onChainChanged(e);
			}
		});
	}
	async onAccountChanged() {
		await this.ethereumProviderAdapter?.onAccountChanged(), await this.solanaProviderAdapter?.onAccountChanged(), await this.tronProviderAdapter?.onAccountChanged();
		let e = l.AccountChanged;
		typeof document < "u" ? document?.dispatchEvent(new Event(e)) : process?.emit("message", e, void 0);
	}
	async onChainChanged(e) {
		e ? await this.getProviderAdapter(e).onChainChanged(e) : (await this.disconnectFromConnector(), x());
	}
	async monitorConnectedAddress(e) {
		await v.monitor(await this.getEthereumAddressByChain(e));
	}
	async getBalances(e, t, n, r, i = !1, a, o = !1) {
		return re(this, e, t, n, r, i, this.generateProofRemotely, a, o);
	}
	async getTotalBalance(e, n, r, i = !1, a, o = !1) {
		let s = r ?? await this.getEthereumAddressByChain(e), c = n ?? this.userKeys, l = await this.getBalances(e, c.getShieldedPrivateKey(), c.getShieldedPublicKey(), s, i, a, o), u = t ? await ne.getPrivateTokens(e, s) : g(e), d = [];
		return u.forEach((e) => {
			let t = e.erc20TokenAddress.toLowerCase(), n = l.get(t), r = {
				token: e,
				balance: n?.balance ?? 0n,
				timestamp: n?.timestamp || "0",
				nfts: n?.nfts || []
			};
			d.push(r);
		}), d;
	}
	async getStuckShieldedBalances(e, t, n, r = !1, i = !1) {
		return (await this.getTotalBalance(e, t, n, r, i, !0)).filter((e) => e.balance > 0n);
	}
	getSupportedPassportLinks() {
		return b;
	}
	checkAccessToken(e, t) {
		return te(this, e, t);
	}
	checkExternalTokenLimitsUSD(e, t, n) {
		return M(e, t, n);
	}
	async getHinkalTreeRootHash(e) {
		if (o(e)) {
			let { hinkalIdl: t, hinkalAddress: n, originalDeployer: r } = c[e].contractData;
			if (!t || !n || !r) throw Error(`Missing Solana configuration for chain ${e}`);
			let i = new $(r), a = m(new $(n), i);
			return O(this.getSolanaProgram(t), a);
		}
		return this.getContractWithFetcherByChainId(e, d.HinkalContract).getRootHash();
	}
	async getAccessTokenTreeRootHash(e) {
		if (o(e)) {
			let { hinkalIdl: t, hinkalAddress: n, originalDeployer: r } = c[e].contractData;
			if (!t || !n || !r) throw Error(`Missing Solana configuration for chain ${e}`);
			let i = new $(r), a = p(new $(n), i);
			return O(this.getSolanaProgram(t), a);
		}
		return this.getContractWithFetcherByChainId(e, d.AccessTokenContract).getRootHash();
	}
	async resetMerkleTreesIfNecessary(e) {
		let t = (await Promise.all((e ?? this.getSupportedChains()).map(async (e) => {
			let [t, n] = await Promise.all([this.getHinkalTreeRootHash(e), this.getAccessTokenTreeRootHash(e)]);
			return {
				chainId: e,
				needsReset: BigInt(t) !== this.merkleTreeHinkalByChain[e].getRootHash() || BigInt(n) !== this.merkleTreeAccessTokenByChain[e].getRootHash()
			};
		}))).filter((e) => e.needsReset).map((e) => e.chainId);
		t.length > 0 && (console.log("resetting merkle tree in resetMerkleTreesIfNecessary for chains:", t), await this.resetMerkle(t));
	}
	async getEthereumAddress() {
		let e = this.ethereumProviderAdapter ?? this.solanaProviderAdapter ?? this.tronProviderAdapter;
		if (!e) throw Error("No provider adapter initialized");
		return e.getAddress();
	}
	getEthereumAddressByChain(e) {
		return this.getProviderAdapter(e).getAddress();
	}
	async getRandomRelay(e, t = !1) {
		return (await v.getIdleRelay(e, t)).relay;
	}
	getGasPrice(e) {
		let t = this.getProviderAdapter(e);
		if (!t) throw Error("Illegal State of providerAdapter in Hinkal: no providerAdapter initialized");
		return t.getGasPrice(e);
	}
	getAPI() {
		return v;
	}
	snapshotsClearInterval() {
		this.getSupportedChains().forEach((e) => {
			this.commitmentsSnapshotServiceByChain[e]?.intervalClear(), this.accessTokenSnapshotServiceByChain[e]?.intervalClear(), this.nullifierSnapshotServiceByChain[e]?.intervalClear();
		});
	}
	checkTokenRegistry(e, t, n) {
		if (o(e)) {
			let { hinkalIdl: r, hinkalAddress: i, originalDeployer: a } = c[e].contractData;
			if (!r || !i || !a) throw Error("missing solana data");
			return ee(this.getSolanaProgram(r), new $(a), t, n);
		}
		return s(e) ? E(t, n, e) : T(this.getContractWithFetcher(e, d.HinkalHelperContract), t, n);
	}
	getRecipientInfo() {
		return B(this);
	}
	async deposit(e, t, n = !0, r = !1) {
		return k(this, e, t, n, r);
	}
	async depositSolana(e, t) {
		return P(this, e, t);
	}
	async depositForOther(e, t, n, r = !0, i = !1) {
		return this.enforceRateLimit(this.depositForOther.name, [
			e,
			t,
			n
		]), A(this, e, t, n, r, i);
	}
	async depositSolanaForOther(e, t, n) {
		return this.enforceRateLimit(this.depositSolanaForOther.name, [
			e,
			t,
			n
		]), F(this, e, t, n);
	}
	async depositAndWithdraw(e, t, n, r, i, a, s, c, l = !0) {
		return o(y([e])) ? Y(this, e, t, n, r, i, a, s, c) : N(this, e, t, n, r, i, a, s, c, l);
	}
	async claimUtxo(e, t, n, r) {
		return o(y([e])) ? fe(this, e, t, n, r) : de(this, e, t, n, r);
	}
	async depositAndBridge(e, t, n, r, i, a, o, s = !0) {
		return ue(this, e, t, n, r, i, a, o, s);
	}
	async prooflessDeposit(e, t, n, r) {
		return o(y(e)) ? Z(this, e, t, n, r) : U(this, e, t, n, r);
	}
	getSolanaProgram(e) {
		if (!this.solanaProviderAdapter) throw Error("No provider adapter initialized");
		if (!("getSolanaProgram" in this.solanaProviderAdapter)) throw Error("Current provider adapter is not a Solana provider adapter");
		return this.solanaProviderAdapter.getSolanaProgram(e);
	}
	getSolanaPublicKey() {
		if (!this.solanaProviderAdapter) throw Error("No provider adapter initialized");
		if (!("getSolanaPublicKey" in this.solanaProviderAdapter)) throw Error("Current provider adapter is not a Solana provider adapter");
		return this.solanaProviderAdapter.getSolanaPublicKey();
	}
	async transfer(e, t, n, r, i, a) {
		return o(y(e)) ? oe(this, e, t, n, r, i, a) : K(this, e, t, n, r, i, a);
	}
	async withdraw(e, t, n, r, i, a, s) {
		return o(y(e)) ? ae(this, e, t, n, i, a, s) : L(this, e, t, n, r, i, a, s);
	}
	async withdrawStuckUtxos(e, t) {
		return pe(this, e, t);
	}
	async swap(e, t, n, r, i, a, s) {
		return o(y(e)) ? this.swapSolana(e, t, r, i, a) : I(this, e, t, n, r, i, a, s);
	}
	async swapSolana(e, t, n, r, i) {
		let a = JSON.parse(n), o = BigInt(a.swapperAccountSalt), { instructionLists: s, addressLookupTableAccount: c } = a.data;
		return se(this, e, t, o, s, c, r, i);
	}
	async actionReceive(e, t, n, r, i, a) {
		if (!i) throw Error("subAccount is required");
		return o(y(e)) ? X(this, e[0], t[0], i, void 0, a) : H(this, e, t, n, r, i, a);
	}
	async actionPrivateWallet(e, t, n, r, i, a, o, s, c, l, u = !1, d, f, p) {
		return this.enforceRateLimit(this.actionPrivateWallet.name, [
			e,
			t,
			n,
			r,
			i,
			a,
			o,
			s,
			c,
			p
		]), ie(this, e, t, n, r, i, a, o, s, c, l, u, d, f, p);
	}
	async proxySwap(e, t, n, r, i, a, s, c, l = !1, u, d) {
		return o(y(e)) ? le(this, e, t, r, a, n, s, c, d) : W(this, e, t, n, r, i, a, s, c, l, u, d);
	}
	async proxyToPrivate(e, t, n, r, i, a, s) {
		return o(y(e)) ? (this.enforceRateLimit(this.proxyToPrivate.name, [
			e[0],
			t[0],
			n,
			r
		]), X(this, e[0], t[0], n, r, s)) : q(this, e, t, r, i, a, n, s);
	}
	async proxySend(e, t, n, r, i, a, s) {
		let c = y(e);
		if (o(c)) return ce(this, e[0], t[0], n, r, s);
		let l = j(this, c, e.map((e) => e.erc20TokenAddress), t, r), u = e.map((e, n) => ({
			token: e,
			amount: -1n * t[n]
		}));
		return await this.actionPrivateWallet(c, [], [], [], l, u, n, i, a, void 0, void 0, void 0, s, void 0);
	}
	async multiSendPrivateRecipients(e, t, n) {
		return this.enforceRateLimit(this.multiSendPrivateRecipients.name, [
			e,
			t,
			n
		]), G(this, e, t, n);
	}
	areMerkleTreeUpdatesDisabled() {
		return this.disableMerkleTreeUpdates;
	}
	updateMerkleTreeUpdates(e) {
		this.disableMerkleTreeUpdates = e;
	}
};
//#endregion
export { me as Hinkal };
