// file: kb_demo_app/frontend/ts/demo3.ts import * as bootstrap from "bootstrap"; import "simplebar"; import ResizeObserver from "resize-observer-polyfill"; import { invoke } from "@tauri-apps/api/core"; import { debug, takeoverConsole } from "@fltsci/tauri-plugin-tracing"; import type { Demo3LocalDexCorpusSearchRequest } from "./bindings/Demo3LocalDexCorpusSearchRequest.ts"; import type { Demo3LocalDexCorpusSearchPayload } from "./bindings/Demo3LocalDexCorpusSearchPayload.ts"; import type { Demo3OnchainDexDiscoveryRequest } from "./bindings/Demo3OnchainDexDiscoveryRequest.ts"; import type { Demo3OnchainDexDiscoveryResult } from "./bindings/Demo3OnchainDexDiscoveryResult.ts"; import type { Demo3OnchainDexPairCandidate } from "./bindings/Demo3OnchainDexPairCandidate.ts"; import type { Demo3LocalDexCorpusSearchResult } from "./bindings/Demo3LocalDexCorpusSearchResult.ts"; import type { Demo3OnchainDexDiscoveryPayload } from "./bindings/Demo3OnchainDexDiscoveryPayload.ts"; (window as Window & typeof globalThis & { bootstrap?: typeof bootstrap }).bootstrap = bootstrap; (window as Window & typeof globalThis & { ResizeObserver?: typeof ResizeObserver }).ResizeObserver = ResizeObserver; interface Demo3Preset { label: string; dexCode: string; programId: string; description: string; } const presets: Demo3Preset[] = [ { label: "PumpSwap", dexCode: "pump_swap", programId: "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA", description: "DEX effectif PumpSwap." }, { label: "Raydium CPMM", dexCode: "raydium_cpmm", programId: "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C", description: "Raydium CPMM." }, { label: "Raydium CLMM", dexCode: "raydium_clmm", programId: "CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK", description: "Raydium CLMM." }, { label: "Raydium AMM v4", dexCode: "raydium_amm_v4", programId: "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8", description: "Raydium AMM v4 legacy. À prouver par corpus avant décodage swap." }, { label: "Raydium Stable Swap", dexCode: "raydium_stable_swap", programId: "5quBtoiQqxF9Jv6KYKctB59NT3gtJD2Y65kdnB1Uev3h", description: "Stable Swap Raydium à vérifier par corpus." }, { label: "Meteora DLMM", dexCode: "meteora_dlmm", programId: "LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo", description: "Meteora DLMM." }, { label: "Meteora DAMM v1", dexCode: "meteora_damm_v1", programId: "Eo7WjKq67rjJQSZxS6z3YkapzY3eMj6Xy8X5EQVn5UaB", description: "Meteora DAMM v1." }, { label: "Meteora DAMM v2", dexCode: "meteora_damm_v2", programId: "cpamdpZCGKUy5JxQXB4dcpGPiikHawvSWAd6mEn1sGG", description: "Meteora DAMM v2." }, { label: "Meteora DBC", dexCode: "meteora_dbc", programId: "dbcij3LWUppWqq96dh6gJWwBifmcGfLSB5D4DuSMaqN", description: "Meteora DBC." }, { label: "Orca Whirlpools", dexCode: "orca_whirlpools", programId: "whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc", description: "Orca Whirlpools CLMM." }, { label: "FluxBeam", dexCode: "fluxbeam", programId: "FLUXubRmkEi2q6K3Y9kBPg9248ggaZVsoSFhtJHSrm1X", description: "FluxBeam." }, { label: "DexLab", dexCode: "dexlab", programId: "DSwpgjMvXhtGn6BsbqmacdBZyfLj6jSWf3HJpdJtmg6N", description: "DexLab Swap/Pool." }, { label: "Aldrin (historical)", dexCode: "aldrin", programId: "AMM55ShdkoGRB5jVYPjWziwk8m5MpwyDgsMWHaMSQWH6", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Aldrin V2 (historical)", dexCode: "aldrin_v2", programId: "CURVGoZn8zycx6FXwwevgBTB2gVvdbGTEpvMJDbgs2t4", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Crema (historical)", dexCode: "crema", programId: "CLMM9tUoggJu2wagPkkqs9eFG4BWhVBZWkP1qv3Sp7tR", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Cropper (historical)", dexCode: "cropper", programId: "H8W3ctz92svYg6mkn1UtGfu2aQr2fnUFHM1RhScEtQDt", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Lifinity V1 (historical)", dexCode: "lifinity_v1", programId: "EewxydAPCCVuNEyrVN68PuSYdQ7wKn27V9Gjeoi8dy3S", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Lifinity V2 (historical)", dexCode: "lifinity_v2", programId: "2wT8Yq49kHgDzXuPxZSaeLaH1qbmGXtEyPy64bL7aD3c", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Mercurial (historical)", dexCode: "mercurial", programId: "MERLuDFBMmsHnsBPZw2sDQZHvXFMwp8EdjudcU2HKky", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Orca V1 (historical)", dexCode: "orca_v1", programId: "DjVE6JNiYqPL2QXyCUUh8rNjHrbz9hXHNYt99MQ59qw1", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Orca V2 (historical)", dexCode: "orca_v2", programId: "9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Phoenix (historical)", dexCode: "phoenix", programId: "PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Saber (historical)", dexCode: "saber", programId: "SSwpkEEcbUqx4vtoEByFjSkhKdCT862DNVb52nZg1UZ", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "OpenBook V2 (historical)", dexCode: "openbook_v2", programId: "opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "OpenBook (historical)", dexCode: "openbook", programId: "srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Fox (historical)", dexCode: "fox", programId: "HyhpEq587ANShDdbx1mP4dTmDZC44CXWft29oYQXDb53", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Sanctum Infinity (historical)", dexCode: "sanctum_infinity", programId: "5ocnV1qiCgaQR8Jb8xWnVbApfaygJ8tNoZfgPwsgx9kx", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Saros (historical)", dexCode: "saros", programId: "SSwapUtytfBdBn1b9NUGG6foMVPtcWgpRU32HToDUZr", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Perps (historical)", dexCode: "perps", programId: "PERPHjGBqRHArX4DySjwM6UJHiR3sWAatqfdBS2qQJu", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "StepN (historical)", dexCode: "stepn", programId: "Dooar9JkhdZ7J3LHN3A7YCuoGRUggXhQaG4kijfLGU2j", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Solayer (historical)", dexCode: "solayer", programId: "endoLNCKTqDn8gSVnN2hDdpgACUPWHZTwoYnnMybpAT", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Penguin (historical)", dexCode: "penguin", programId: "PSwapMdSai8tjrEXcxFeQth87xC4rRsa4VA5mhGhXkP", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Sanctum (historical)", dexCode: "sanctum", programId: "stkitrT1Uoy18Dk1fTrgPw8W6MVzoCfYoAFT4MLsmhq", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Guacswap (historical)", dexCode: "guacswap", programId: "Gswppe6ERWKpUTXvRPfXdzHhiCyJvLadVvXGfdpBqcE1", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Oasis (historical)", dexCode: "oasis", programId: "9tKE7Mbmj4mxDjWatikzGAtkoWosiiZX9y6J4Hfm2R8H", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Saber Decimals (historical)", dexCode: "saber_decimals", programId: "DecZY86MU5Gj7kppfUCEmd4LbXXuyZH1yHaP2NTqdiZB", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Stabble Stable Swap (historical)", dexCode: "stabble_stable_swap", programId: "swapNyd8XiQwJ6ianp9snpu4brUqFxadzvHebnAXjJZ", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Stabble Weighted Swap (historical)", dexCode: "stabble_weighted_swap", programId: "swapFpHZwjELNnjvThjajtiVmkz3yPQEHjLtka2fwHW", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "1DEX (historical)", dexCode: "one_dex", programId: "DEXYosS6oEGvk8uCDayvwEZz4qEyDJRf9nFgYCaqPMTm", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "SolFi (historical)", dexCode: "solfi", programId: "SoLFiHG9TfgtdUXUjWAxi3LtvYuFyDLVhBWxdMZxyCe", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Moonshot (historical)", dexCode: "moonshot", programId: "MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Bonkswap (historical)", dexCode: "bonkswap", programId: "BSwp6bEBihVLdqJRKGgzjcGLHkcTuzmSo1TQkHepzH8p", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Invariant (historical)", dexCode: "invariant", programId: "HyaB3W9q6XdA5xwpU4XnSZV94htfmbmqJXZcEbRaJutt", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Token Swap (historical)", dexCode: "token_swap", programId: "SwaPpA9LAaLfeLi3a68M4DjnLqgtticKg6CnyNwgAC8", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Helium Network (historical)", dexCode: "helium_network", programId: "treaf4wWBBty3fHdyBpo35Mz84M8k3heKXmjmi9vFt5", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Raydium Legacy V2 (historical)", dexCode: "raydium_legacy_v2", programId: "27haf8L6oxUeXrHrgEgsexjSY5hbVUWEmvv9Nyxg8vQv", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Raydium Legacy V3 (historical)", dexCode: "raydium_legacy_v3", programId: "7quYqsZdpWSZ3qgDextersDqoKjZy7aCgwHBBfRb7KPt", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Serum V3 (historical)", dexCode: "serum_v3", programId: "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Mango Private Pools (historical)", dexCode: "mango_private_pools", programId: "AtdP2iyfh6xBGwVZzHvY73E7uKKkZBTH2siHh3ZuEf1P", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Marinade Liquid Staking (historical)", dexCode: "marinade_liquid_staking", programId: "MarBmsSgKXdrN1egZf5sqe1TMai9K1rChYNDJgjq7aD", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Step Finance Pools (historical)", dexCode: "step_finance_pools", programId: "StepAscQoEioFxxWGnh2sLBDFp9d8rvKz2Yp39iDpyT", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Francium Yield Pools (historical)", dexCode: "francium_yield_pools", programId: "FC81tbGt6JWRXidaWYFXxGnTk4VgobhJHATvTRVMqgWj", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Cropper Legacy (historical)", dexCode: "cropper_legacy", programId: "CyZuD7RPDcrqCGbNvzrNVs1zpCQehqp7SuXB7rdFKSzo", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Dexlab Beta (historical)", dexCode: "dexlab_beta", programId: "9qvG1zP8ZzY1sTnExx7mkyxhW1063YHVYZxMYz2HkM4m", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Marinade Governance (historical)", dexCode: "marinade_governance", programId: "GovER5Lthms3bLBqWub97yVrMmEogzX7xNjdXpPPCVZw", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Serum DAO (historical)", dexCode: "serum_dao", programId: "SPoo1Ku8WFXoNDMHPsrGSTSG1Y47rzgn41SLUNakuHy", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Port Finance (historical)", dexCode: "port_finance", programId: "Port7uDYB3wk6GJAw4KT1WpTeMtSu9bTcChBHkX2LfR", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Solend Classic (historical)", dexCode: "solend_classic", programId: "So1endDq2YkqhipRh3WViPa8hdiSpxWy6z3Z6tMCpAo", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Hyperspace NFT AMM (historical)", dexCode: "hyperspace_nft_amm", programId: "HYPERfwdTjyJ2SCaKHmpF2MtrXqWxrsotYDsTrshHWq8", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Magic Eden NFT AMM (historical)", dexCode: "magic_eden_nft_amm", programId: "MEisE1HzehtrDpAAT8PnLHjpSSkRYakotTuJRPjTpo8", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Raydium Staking Early (historical)", dexCode: "raydium_staking_early", programId: "EhhTKczWMGQt46ynNeRX1WfeagwwJd7ufHvCDjRxjo5Q", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Orca Aquafarm V1 (historical)", dexCode: "orca_aquafarm_v1", programId: "82yxjeMsvaURa4MbZZ7WZZHfobirZYkH1zF8fmeGtyaQ", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "Quarry Merge Mining (historical)", dexCode: "quarry_merge_mining", programId: "QMNeHCGYnLVDn1icRAfQZpjPLBNkfGbSKRB83G5d8KB", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "SWAB Finance Beta (historical)", dexCode: "swab_finance_beta", programId: "SWABxNGyxEBVoNRGn6RvYBt5UqercSE5PBHuJeYXYHq", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "CRAFT Early (historical)", dexCode: "craft_early", programId: "CrAFTUv7zKXBaS5471aBiARBu6x7nP4rDzr8xwBewbr1", description: "Program id historique importé depuis entities.py; à vérifier par corpus." }, { label: "metaDAO", dexCode: "metadao", programId: "", description: "DEX à vérifier. Aucun program id n'est inventé." }, { label: "Printr", dexCode: "printr", programId: "", description: "DEX à vérifier. Aucun program id n'est inventé." }, ]; let lastResultJson = ""; function byId(id: string): T { const element = document.getElementById(id); if (element === null) { throw new Error(`missing element #${id}`); } return element as T; } function valueOrNull(value: string): string | null { const trimmed = value.trim(); return trimmed === "" ? null : trimmed; } function isSolanaAddressLike(value: string): boolean { const trimmed = value.trim(); if (trimmed.length < 32 || trimmed.length > 44) { return false; } return /^[1-9A-HJ-NP-Za-km-z]+$/.test(trimmed); } function splitSourceAddresses(value: string): string[] { const seen = new Set(); const addresses: string[] = []; for (const token of value.split(/[\s,;]+/g)) { const trimmed = token.trim(); if (trimmed === "" || seen.has(trimmed)) { continue; } seen.add(trimmed); addresses.push(trimmed); } return addresses; } function isSolanaSignatureLike(value: string): boolean { const trimmed = value.trim(); if (trimmed.length < 64 || trimmed.length > 128) { return false; } return /^[1-9A-HJ-NP-Za-km-z]+$/.test(trimmed); } function validateOptionalSignature(value: string | null, label: string): void { if (value === null || value.trim() === "") { return; } if (!isSolanaSignatureLike(value)) { throw new Error(`${label} must be a valid Solana transaction signature.`); } } function validateOnchainRequest(request: Demo3OnchainDexDiscoveryRequest): void { const addresses = request.sourceAddresses ?? []; if (request.signatureSource === "address" && addresses.length === 0) { throw new Error("Signature source is 'address': provide at least one Solana account, pool, vault, position, config or mint address."); } for (const address of addresses) { if (!isSolanaAddressLike(address)) { throw new Error(`Invalid source address '${address}'. Provide Solana account addresses separated by commas, spaces or new lines.`); } } validateOptionalSignature(request.beforeSignature, "Before signature"); validateOptionalSignature(request.untilSignature, "Until signature"); if (request.programId !== null && !isSolanaAddressLike(request.programId)) { throw new Error("Program id filter must be a valid Solana program id, or empty when using a preset that resolves it."); } } function numberValueOrNull(value: string): number | null { const trimmed = value.trim(); if (trimmed === "") { return null; } const parsed = Number.parseInt(trimmed, 10); return Number.isFinite(parsed) ? parsed : null; } function intValue(id: string, fallback: number): number { const parsed = Number.parseInt(byId(id).value, 10); return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback; } function selectedTargetEvents(): string[] { return Array.from(document.querySelectorAll('input[name="demo3TargetEventInput"]:checked')) .map((input) => input.value.trim()) .filter((value) => value !== ""); } function readTargetEventFilter(): string | null { const selected = selectedTargetEvents(); return selected.length === 0 ? null : selected.join(","); } function targetEventLabel(targetEvent: string | null): string { return targetEvent === null || targetEvent.trim() === "" ? "any" : targetEvent; } function clearTargetEventFilters(): void { document.querySelectorAll('input[name="demo3TargetEventInput"]').forEach((input) => { input.checked = false; }); } function escapeHtml(value: string): string { return value .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } function shortText(value: string | null, maxLength: number): string { if (value === null) { return "-"; } if (value.length <= maxLength) { return value; } return `${value.slice(0, maxLength)}…`; } function shortList(values: string[], maxItems: number, itemLength: number): string { if (values.length === 0) { return "-"; } return values.slice(0, maxItems).map((value) => shortText(value, itemLength)).join(", "); } function candidateAccountList(accounts: Demo3OnchainDexPairCandidate["candidatePoolAccounts"], maxItems: number): string { if (accounts.length === 0) { return "-"; } return accounts.slice(0, maxItems).map((account) => shortText(account.address, 14)).join(", "); } function tokenDeltaList(candidate: Demo3OnchainDexPairCandidate): string { if (candidate.tokenBalanceDeltas.length === 0) { return "-"; } return candidate.tokenBalanceDeltas.slice(0, 4).map((delta) => { const amount = delta.deltaRaw ?? "?"; return `${shortText(delta.mint, 10)}:${amount}`; }).join(", "); } function appendLogLine(line: string): void { const textarea = byId("demo3LogTextarea"); const timestamp = new Date().toLocaleTimeString("fr-CH", { hour12: false }); const lines = textarea.value === "" ? [] : textarea.value.split("\n"); lines.push(`[${timestamp}] ${line}`); textarea.value = lines.slice(-400).join("\n"); textarea.scrollTop = textarea.scrollHeight; } function setStatus(label: string, cssClass: string): void { const badge = byId("demo3StatusBadge"); badge.className = `badge ${cssClass}`; badge.textContent = label; } function populatePresetSelect(): void { const select = byId("demo3PresetSelect"); select.innerHTML = ''; presets.forEach((preset, index) => { const option = document.createElement("option"); option.value = String(index); option.textContent = preset.label; select.appendChild(option); }); } function applyPreset(indexText: string): void { if (indexText === "") { return; } const index = Number.parseInt(indexText, 10); if (!Number.isFinite(index) || index < 0 || index >= presets.length) { return; } const preset = presets[index]; byId("demo3DexCodeInput").value = preset.dexCode; byId("demo3ProgramIdInput").value = preset.programId; byId("demo3PresetHelp").textContent = preset.description; } function readOnchainRequest(): Demo3OnchainDexDiscoveryRequest { const sourceAddresses = splitSourceAddresses(byId("demo3SourceAddressInput").value); return { dexCode: valueOrNull(byId("demo3DexCodeInput").value), programId: valueOrNull(byId("demo3ProgramIdInput").value), signatureSource: valueOrNull(byId("demo3SignatureSourceSelect").value), sourceAddress: sourceAddresses.length === 1 ? sourceAddresses[0] : null, sourceAddresses, beforeSignature: valueOrNull(byId("demo3BeforeSignatureInput").value), untilSignature: valueOrNull(byId("demo3UntilSignatureInput").value), maxPages: intValue("demo3MaxPagesInput", 1), scanOrder: valueOrNull(byId("demo3ScanOrderSelect").value), targetEvent: readTargetEventFilter(), excludeSwaps: byId("demo3ExcludeSwapsInput").checked, includeFailed: byId("demo3IncludeFailedInput").checked, httpRole: byId("demo3HttpRoleInput").value.trim() || "history_backfill", signatureLimit: intValue("demo3SignatureLimitInput", 50), transactionLimit: intValue("demo3TransactionLimitInput", 25), candidateLimit: intValue("demo3CandidateLimitInput", 25), }; } function readLocalRequest(): Demo3LocalDexCorpusSearchRequest { return { dexCode: valueOrNull(byId("demo3DexCodeInput").value), programId: valueOrNull(byId("demo3ProgramIdInput").value), pairId: numberValueOrNull(byId("demo3PairIdInput").value), poolAddress: valueOrNull(byId("demo3PoolAddressInput").value), tokenMint: valueOrNull(byId("demo3TokenMintInput").value), signature: valueOrNull(byId("demo3SignatureInput").value), limit: intValue("demo3CandidateLimitInput", 25), }; } function clearFilters(): void { byId("demo3DexCodeInput").value = ""; byId("demo3ProgramIdInput").value = ""; byId("demo3SignatureSourceSelect").value = "program_id"; byId("demo3SourceAddressInput").value = ""; byId("demo3BeforeSignatureInput").value = ""; byId("demo3UntilSignatureInput").value = ""; byId("demo3MaxPagesInput").value = "1"; byId("demo3ScanOrderSelect").value = "newest_first"; byId("demo3PairIdInput").value = ""; byId("demo3PoolAddressInput").value = ""; byId("demo3TokenMintInput").value = ""; byId("demo3SignatureInput").value = ""; clearTargetEventFilters(); byId("demo3ExcludeSwapsInput").checked = false; byId("demo3IncludeFailedInput").checked = true; byId("demo3PresetSelect").value = ""; byId("demo3PresetHelp").textContent = "Choisis un DEX ou saisis un program id manuellement."; } function renderOnchainResult(result: Demo3OnchainDexDiscoveryResult): void { byId("demo3SummarySignatureCount").textContent = String(result.fetchedSignatureCount); byId("demo3SummaryUniqueFetchedSignatureCount").textContent = String(result.uniqueFetchedSignatureCount); byId("demo3SummaryFetchedPageCount").textContent = String(result.fetchedSignaturePageCount); byId("demo3SummaryUniqueSignatureCount").textContent = String(result.uniqueSignatureCount); byId("demo3SummaryFetchedTxCount").textContent = String(result.fetchedTransactionCount); byId("demo3SummaryMissingTxCount").textContent = String(result.missingTransactionCount); byId("demo3SummaryFailedTxCount").textContent = String(result.failedTransactionCount); byId("demo3SummarySkippedFailedTxCount").textContent = String(result.skippedFailedTransactionCount); byId("demo3SummarySkippedSwapTxCount").textContent = String(result.skippedSwapLogTransactionCount); byId("demo3SummaryExtractedCandidateCount").textContent = String(result.extractedCandidateCount); byId("demo3SummaryRejectedCandidateCount").textContent = String(result.targetRejectedCandidateCount); byId("demo3SummaryCandidateCount").textContent = String(result.candidateCount); const targetEvent = targetEventLabel(result.request.targetEvent); const sourceText = result.resolvedSignatureAddresses.length === 0 ? result.resolvedSignatureAddress : result.resolvedSignatureAddresses.join(","); byId("demo3TargetText").textContent = `${result.resolvedDexCode ?? "custom"} / program=${result.resolvedProgramId} / source=${result.resolvedSignatureSource}:${sourceText} / target=${targetEvent} / order=${result.request.scanOrder ?? "newest_first"}`; byId("demo3UniqueSignatureText").textContent = result.uniqueBackfillSignatures.length === 0 ? "-" : result.uniqueBackfillSignatures.join(", "); byId("demo3NextBeforeText").textContent = result.nextBeforeByAddress.length === 0 ? "-" : result.nextBeforeByAddress.map((cursor) => `${cursor.address}:${cursor.nextBeforeSignature ?? "-"}`).join(" | "); renderRejectedSummary(result); renderOnchainCandidates(result.candidates); } function renderRejectedSummary(result: Demo3OnchainDexDiscoveryResult): void { const body = byId("demo3RejectedSummaryTableBody"); if (result.rejectedCandidateSummary.length === 0) { body.innerHTML = 'No rejected candidate summary.'; return; } body.innerHTML = result.rejectedCandidateSummary.map((summary) => ` ${escapeHtml(summary.candidateKind)} ${escapeHtml(shortText(summary.instructionDataPrefix, 16))} ${escapeHtml(summary.instructionName ?? "-")} ${escapeHtml(summary.rejectionReason)} ${summary.count} `).join(""); } function renderOnchainCandidates(candidates: Demo3OnchainDexPairCandidate[]): void { const body = byId("demo3OnchainCandidateTableBody"); if (candidates.length === 0) { body.innerHTML = 'No on-chain candidate.'; return; } body.innerHTML = candidates.map((candidate) => { const verifiedPool = candidate.verifiedPoolAddress; const firstCandidatePool = candidate.candidatePoolAccounts.length > 0 ? candidate.candidatePoolAccounts[0].address : null; const poolForFilter = verifiedPool ?? candidate.poolAddress ?? firstCandidatePool; if (poolForFilter !== null) { byId("demo3PoolAddressInput").value = poolForFilter; } if (candidate.tokenAMint !== null && byId("demo3TokenMintInput").value.trim() === "") { byId("demo3TokenMintInput").value = candidate.tokenAMint; } if (candidate.tokenAMint === null && candidate.observedTokenMints.length > 0 && byId("demo3TokenMintInput").value.trim() === "") { byId("demo3TokenMintInput").value = candidate.observedTokenMints[0]; } byId("demo3SignatureInput").value = candidate.signature; const accountTitle = candidate.candidatePoolAccounts.map((account) => `${account.address} (${account.reason})`).join("\n"); const vaultTitle = candidate.candidateTokenVaultAccounts.map((account) => `${account.address} (${account.reason})`).join("\n"); return ` ${escapeHtml(shortText(candidate.signature, 18))} ${candidate.slot ?? "-"} ${escapeHtml(candidate.candidateKind)} ${escapeHtml(candidate.confidence)} ${escapeHtml(shortText(candidate.instructionDataPrefix, 14))} ${escapeHtml(shortText(verifiedPool, 14))} ${escapeHtml(shortText(candidate.tokenAMint, 14))} ${escapeHtml(shortText(candidate.tokenBMint, 14))} ${escapeHtml(shortList(candidate.observedTokenMints, 3, 10))} ${escapeHtml(tokenDeltaList(candidate))} ${escapeHtml(candidateAccountList(candidate.candidatePoolAccounts, 3))}
vaults: ${escapeHtml(candidateAccountList(candidate.candidateTokenVaultAccounts, 2))} ${escapeHtml(candidate.backfillHint)} `; }).join(""); } function renderLocalResult(result: Demo3LocalDexCorpusSearchResult): void { byId("demo3SummaryLocalPairCount").textContent = String(result.summary.pairCount); const body = byId("demo3LocalPoolPairTableBody"); if (result.poolPairSamples.length === 0) { body.innerHTML = 'No local pool/pair sample.'; return; } body.innerHTML = result.poolPairSamples.map((sample) => ` ${escapeHtml(sample.dexCode ?? "-")} ${escapeHtml(shortText(sample.poolAddress, 16))} ${sample.pairId ?? "-"} ${escapeHtml(sample.pairSymbol ?? "-")} ${escapeHtml(sample.baseSymbol ?? shortText(sample.baseMint, 12))} ${escapeHtml(sample.quoteSymbol ?? shortText(sample.quoteMint, 12))} ${sample.tradeEventCount} ${sample.pairCandleCount} `).join(""); } async function discoverOnchain(): Promise { const request = readOnchainRequest(); try { validateOnchainRequest(request); } catch (error) { setStatus("error", "text-bg-danger"); appendLogLine(`on-chain discovery rejected locally: ${String(error)}`); return; } setStatus("running", "text-bg-warning"); appendLogLine(`on-chain discovery dex='${request.dexCode ?? ""}' program='${request.programId ?? ""}' source='${request.signatureSource ?? "program_id"}:${request.sourceAddresses.join(",")}' target='${targetEventLabel(request.targetEvent)}' pages='${request.maxPages}' order='${request.scanOrder ?? "newest_first"}' before='${request.beforeSignature ?? ""}' until='${request.untilSignature ?? ""}' excludeSwaps='${request.excludeSwaps}' role='${request.httpRole}'`); try { const payload = await invoke("demo3_discover_onchain_dex_pairs", { request }); lastResultJson = payload.resultJson; byId("demo3JsonTextarea").value = payload.resultJson; renderOnchainResult(payload.result); setStatus("ok", "text-bg-success"); appendLogLine(`on-chain discovery completed: candidates='${payload.result.candidateCount}' unique='${payload.result.uniqueSignatureCount}' signatures='${payload.result.fetchedSignatureCount}' uniqueFetched='${payload.result.uniqueFetchedSignatureCount}' pages='${payload.result.fetchedSignaturePageCount}' extracted='${payload.result.extractedCandidateCount}' rejected='${payload.result.targetRejectedCandidateCount}' skippedSwapTx='${payload.result.skippedSwapLogTransactionCount}'`); } catch (error) { setStatus("error", "text-bg-danger"); appendLogLine(`on-chain discovery failed: ${String(error)}`); } } async function searchLocalDb(): Promise { const request = readLocalRequest(); setStatus("running", "text-bg-warning"); appendLogLine("local DB search started"); try { const payload = await invoke("demo3_search_local_dex_corpus", { request }); lastResultJson = payload.resultJson; byId("demo3JsonTextarea").value = payload.resultJson; renderLocalResult(payload.result); setStatus("ok", "text-bg-success"); appendLogLine(`local DB search completed: pairs='${payload.result.summary.pairCount}' tx='${payload.result.summary.transactionCount}'`); } catch (error) { setStatus("error", "text-bg-danger"); appendLogLine(`local DB search failed: ${String(error)}`); } } async function copyJson(): Promise { if (lastResultJson === "") { appendLogLine("nothing to copy"); return; } try { await navigator.clipboard.writeText(lastResultJson); appendLogLine("JSON copied to clipboard"); } catch (error) { appendLogLine(`copy failed: ${String(error)}`); } } function init(): void { takeoverConsole(); void debug("demo3 on-chain discovery initialized"); debug("demo3 window loaded"); const sidebarToggle = document.querySelector('#sidebarToggle'); if (sidebarToggle) { // restaurer l’état depuis localStorage if (localStorage.getItem('sidebar-toggle') === 'true') { document.body.classList.add('sidenav-toggled'); } sidebarToggle.addEventListener('click', (event) => { event.preventDefault(); document.body.classList.toggle('sidenav-toggled'); localStorage.setItem('sidebar-toggle', document.body.classList.contains('sidenav-toggled') ? 'true' : 'false'); }); } const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]'); Array.from(tooltipTriggerList).map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl)); const toastElList = document.querySelectorAll('.toast'); Array.from(toastElList).map(toastEl => new bootstrap.Toast(toastEl)); const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="popover"]'); Array.from(popoverTriggerList).map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl)); const gobackto = location.pathname + location.search; document.querySelectorAll('a[data-setlang]').forEach((a) => { const href = a.getAttribute("href"); if (!href) return; // pas de href => on ignore const url = new URL(href, location.origin); url.searchParams.set("gobackto", gobackto); // conserve une URL relative (path + query) a.setAttribute("href", url.pathname + "?" + url.searchParams.toString()); }); populatePresetSelect(); byId("demo3PresetSelect").addEventListener("change", (event) => { applyPreset((event.target as HTMLSelectElement).value); }); byId("demo3DiscoverButton").addEventListener("click", () => { void discoverOnchain(); }); byId("demo3LocalSearchButton").addEventListener("click", () => { void searchLocalDb(); }); byId("demo3ClearFiltersButton").addEventListener("click", clearFilters); byId("demo3CopyJsonButton").addEventListener("click", () => { void copyJson(); }); byId("demo3ClearLogButton").addEventListener("click", () => { byId("demo3LogTextarea").value = ""; }); appendLogLine("ready"); } document.addEventListener("DOMContentLoaded", init);