import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
import { join } from "node:path";
//#region extensions/crypto/src/services/tx-ledger.ts
/**
* Event-Sourced Transaction Ledger — append-only log of every on-chain action.
*
* Inspired by Lemon's event-sourced game engine and IronClaw's audit boundary.
*
* Every on-chain action the agent takes (swap, transfer, bridge, approve, launch,
* etc.) is recorded as an immutable event. The ledger provides:
*
* 1. Complete audit trail for regulatory/tax purposes
* 2. Foundation for heartbeat monitoring (knows all open positions)
* 3. Replay capability — can reconstruct portfolio state from events
* 4. Cross-session continuity — survives restarts
*
* Events are append-only: once written, they are never modified or deleted.
* Each event gets a monotonically increasing sequence number.
*/
const CHAIN_NAMES = {
	1: "ethereum",
	8453: "base",
	42161: "arbitrum",
	10: "optimism",
	137: "polygon"
};
const TOOL_EVENT_MAP = {
	defi_swap: "swap",
	transfer: "transfer",
	bridge: "bridge",
	permit2: "permit2",
	clawnch_launch: "launch",
	clawnch_fees: "claim_fees",
	liquidity: "add_liquidity",
	compound_action: "compound_action",
	bankr_launch: "bankr_launch",
	bankr_automate: "bankr_automate",
	bankr_polymarket: "bankr_polymarket",
	bankr_leverage: "bankr_leverage",
	defi_lend: "lend_supply",
	approvals: "approval_revoke",
	defi_stake: "stake",
	nft: "nft_transfer",
	privacy: "privacy_deposit",
	yield: "yield_deposit",
	governance: "governance_vote",
	safe: "safe_propose",
	airdrop: "airdrop_check",
	manage_orders: "order_create",
	hummingbot: "hummingbot_action",
	molten: "molten_action",
	clawnx: "clawnx_post"
};
/**
* Map defi_lend action names to specific event types.
* Used by the lending tool to record granular events.
*/
const LEND_ACTION_EVENT_MAP = {
	supply: "lend_supply",
	borrow: "lend_borrow",
	repay: "lend_repay",
	withdraw: "lend_withdraw"
};
/**
* Map defi_stake action names to specific event types.
*/
const STAKE_ACTION_EVENT_MAP = {
	stake: "stake",
	unstake: "stake_unstake",
	wrap: "stake_wrap",
	unwrap: "stake_unwrap"
};
/**
* Map nft action names to specific event types.
*/
const NFT_ACTION_EVENT_MAP = {
	transfer: "nft_transfer",
	buy: "nft_buy",
	list: "nft_list"
};
/**
* Map privacy action names to specific event types.
*/
const PRIVACY_ACTION_EVENT_MAP = {
	deposit: "privacy_deposit",
	withdraw: "privacy_withdraw",
	transfer: "privacy_transfer"
};
/**
* Map yield action names to specific event types.
*/
const YIELD_ACTION_EVENT_MAP = {
	deposit: "yield_deposit",
	withdraw: "yield_withdraw"
};
/**
* Map governance action names to specific event types.
*/
const GOVERNANCE_ACTION_EVENT_MAP = {
	vote: "governance_vote",
	delegate: "governance_delegate"
};
/**
* Map safe action names to specific event types.
* Safe operations are off-chain (REST API) but recorded for audit trail.
*/
const SAFE_ACTION_EVENT_MAP = {
	propose: "safe_propose",
	confirm: "safe_confirm"
};
/**
* Map airdrop action names to specific event types.
*/
const AIRDROP_ACTION_EVENT_MAP = {
	check: "airdrop_check",
	check_all: "airdrop_check",
	claim: "airdrop_claim"
};
/**
* Map manage_orders action names to specific event types.
*/
const ORDER_ACTION_EVENT_MAP = {
	create: "order_create",
	cancel: "order_cancel"
};
function toolToEventType(toolName) {
	return TOOL_EVENT_MAP[toolName] ?? "unknown";
}
function chainIdToName(chainId) {
	return CHAIN_NAMES[chainId] ?? String(chainId);
}
var TxLedger = class {
	events = [];
	nextSeq = 1;
	dirty = false;
	ledgerPath;
	constructor() {
		this.ledgerPath = this.getLedgerPath();
		this.loadFromDisk();
	}
	/**
	* Append a new event to the ledger. Returns the assigned sequence number.
	*/
	append(event) {
		const now = Date.now();
		const full = {
			...event,
			seq: this.nextSeq++,
			timestamp: new Date(now).toISOString(),
			timestampMs: now
		};
		this.events.push(full);
		this.dirty = true;
		this.persistAppend(full);
		return full;
	}
	/**
	* Update the status of an existing event (e.g., pending → confirmed).
	* This is the ONLY mutation allowed — and it creates a new event rather
	* than modifying the original, preserving the append-only invariant.
	*/
	updateStatus(seq, status, updates) {
		const original = this.events.find((e) => e.seq === seq);
		if (!original) return null;
		return this.append({
			type: original.type,
			userId: original.userId,
			txHash: updates?.txHash ?? original.txHash,
			chainId: original.chainId,
			chain: original.chain,
			from: original.from,
			to: original.to,
			status,
			summary: `[status update] ${original.summary}`,
			data: {
				...original.data,
				_refSeq: original.seq,
				_previousStatus: original.status
			},
			gasCostUsd: updates?.gasCostUsd ?? original.gasCostUsd,
			tool: original.tool,
			error: updates?.error ?? original.error
		});
	}
	/**
	* Query events with optional filters. Returns newest-first.
	*/
	query(q = {}) {
		let results = [...this.events];
		if (q.userId) results = results.filter((e) => e.userId === q.userId);
		if (q.types?.length) results = results.filter((e) => q.types.includes(e.type));
		if (q.chainId) results = results.filter((e) => e.chainId === q.chainId);
		if (q.status) results = results.filter((e) => e.status === q.status);
		if (q.afterMs) results = results.filter((e) => e.timestampMs > q.afterMs);
		if (q.beforeMs) results = results.filter((e) => e.timestampMs < q.beforeMs);
		if (q.afterSeq) results = results.filter((e) => e.seq > q.afterSeq);
		results.sort((a, b) => b.seq - a.seq);
		if (q.limit) results = results.slice(0, q.limit);
		return results;
	}
	/**
	* Get a single event by sequence number.
	*/
	getBySeq(seq) {
		return this.events.find((e) => e.seq === seq) ?? null;
	}
	/**
	* Get the most recent event for a given tx hash.
	*/
	getByTxHash(txHash) {
		for (let i = this.events.length - 1; i >= 0; i--) if (this.events[i].txHash === txHash) return this.events[i];
		return null;
	}
	/**
	* Get aggregate statistics.
	*/
	getStats() {
		const byType = {};
		const byStatus = {};
		const byChain = {};
		for (const e of this.events) {
			byType[e.type] = (byType[e.type] ?? 0) + 1;
			byStatus[e.status] = (byStatus[e.status] ?? 0) + 1;
			byChain[e.chain] = (byChain[e.chain] ?? 0) + 1;
		}
		return {
			totalEvents: this.events.length,
			byType,
			byStatus,
			byChain,
			oldestEventMs: this.events.length > 0 ? this.events[0].timestampMs : null,
			newestEventMs: this.events.length > 0 ? this.events[this.events.length - 1].timestampMs : null
		};
	}
	/**
	* Get the total number of events.
	*/
	get size() {
		return this.events.length;
	}
	getLedgerPath() {
		const dir = process.env.OPENCLAWNCH_TX_DIR ? join(process.env.OPENCLAWNCH_TX_DIR, "..", "ledger") : join(process.env.HOME ?? "/tmp", ".openclawnch", "ledger");
		if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
		return join(dir, "tx-ledger.jsonl");
	}
	loadFromDisk() {
		try {
			if (!existsSync(this.ledgerPath)) return;
			const lines = readFileSync(this.ledgerPath, "utf8").split("\n").filter((l) => l.trim());
			for (const line of lines) try {
				const event = JSON.parse(line);
				this.events.push(event);
				if (event.seq >= this.nextSeq) this.nextSeq = event.seq + 1;
			} catch {}
		} catch {}
	}
	persistAppend(event) {
		try {
			appendFileSync(this.ledgerPath, JSON.stringify(event) + "\n", "utf8");
			this.dirty = false;
		} catch {}
	}
};
let _instance = null;
function getTxLedger() {
	if (!_instance) _instance = new TxLedger();
	return _instance;
}
function resetTxLedger() {
	_instance = null;
}
//#endregion
export { AIRDROP_ACTION_EVENT_MAP, GOVERNANCE_ACTION_EVENT_MAP, LEND_ACTION_EVENT_MAP, NFT_ACTION_EVENT_MAP, ORDER_ACTION_EVENT_MAP, PRIVACY_ACTION_EVENT_MAP, SAFE_ACTION_EVENT_MAP, STAKE_ACTION_EVENT_MAP, YIELD_ACTION_EVENT_MAP, chainIdToName, getTxLedger, resetTxLedger, toolToEventType };

//# sourceMappingURL=tx-ledger.mjs.map