0.7.43-E5C

This commit is contained in:
2026-05-27 11:28:36 +02:00
parent 69c8f6c957
commit d9558a5c16
28 changed files with 4451 additions and 325 deletions

View File

@@ -7,11 +7,11 @@ 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";
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;
@@ -37,6 +37,59 @@ const presets: Demo3Preset[] = [
{ 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é." },
];
@@ -56,6 +109,26 @@ function valueOrNull(value: string): string | null {
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 validateOnchainRequest(request: Demo3OnchainDexDiscoveryRequest): void {
if (request.signatureSource === "address") {
const sourceAddress = request.sourceAddress ?? "";
if (!isSolanaAddressLike(sourceAddress)) {
throw new Error("Signature source is 'address': Source address must be a real Solana account address, pool, vault, position, config or mint. It cannot be empty or the literal value 'address'.");
}
}
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 === "") {
@@ -157,6 +230,11 @@ function readOnchainRequest(): Demo3OnchainDexDiscoveryRequest {
return {
dexCode: valueOrNull(byId<HTMLInputElement>("demo3DexCodeInput").value),
programId: valueOrNull(byId<HTMLInputElement>("demo3ProgramIdInput").value),
signatureSource: valueOrNull(byId<HTMLSelectElement>("demo3SignatureSourceSelect").value),
sourceAddress: valueOrNull(byId<HTMLInputElement>("demo3SourceAddressInput").value),
targetEvent: valueOrNull(byId<HTMLSelectElement>("demo3TargetEventSelect").value),
excludeSwaps: byId<HTMLInputElement>("demo3ExcludeSwapsInput").checked,
includeFailed: byId<HTMLInputElement>("demo3IncludeFailedInput").checked,
httpRole: byId<HTMLInputElement>("demo3HttpRoleInput").value.trim() || "history_backfill",
signatureLimit: intValue("demo3SignatureLimitInput", 50),
transactionLimit: intValue("demo3TransactionLimitInput", 25),
@@ -179,28 +257,57 @@ function readLocalRequest(): Demo3LocalDexCorpusSearchRequest {
function clearFilters(): void {
byId<HTMLInputElement>("demo3DexCodeInput").value = "";
byId<HTMLInputElement>("demo3ProgramIdInput").value = "";
byId<HTMLSelectElement>("demo3SignatureSourceSelect").value = "program_id";
byId<HTMLInputElement>("demo3SourceAddressInput").value = "";
byId<HTMLInputElement>("demo3PairIdInput").value = "";
byId<HTMLInputElement>("demo3PoolAddressInput").value = "";
byId<HTMLInputElement>("demo3TokenMintInput").value = "";
byId<HTMLInputElement>("demo3SignatureInput").value = "";
byId<HTMLSelectElement>("demo3TargetEventSelect").value = "";
byId<HTMLInputElement>("demo3ExcludeSwapsInput").checked = false;
byId<HTMLInputElement>("demo3IncludeFailedInput").checked = true;
byId<HTMLSelectElement>("demo3PresetSelect").value = "";
byId<HTMLElement>("demo3PresetHelp").textContent = "Choisis un DEX ou saisis un program id manuellement.";
}
function renderOnchainResult(result: Demo3OnchainDexDiscoveryResult): void {
byId<HTMLElement>("demo3SummarySignatureCount").textContent = String(result.fetchedSignatureCount);
byId<HTMLElement>("demo3SummaryUniqueSignatureCount").textContent = String(result.uniqueSignatureCount);
byId<HTMLElement>("demo3SummaryFetchedTxCount").textContent = String(result.fetchedTransactionCount);
byId<HTMLElement>("demo3SummaryMissingTxCount").textContent = String(result.missingTransactionCount);
byId<HTMLElement>("demo3SummaryFailedTxCount").textContent = String(result.failedTransactionCount);
byId<HTMLElement>("demo3SummarySkippedFailedTxCount").textContent = String(result.skippedFailedTransactionCount);
byId<HTMLElement>("demo3SummarySkippedSwapTxCount").textContent = String(result.skippedSwapLogTransactionCount);
byId<HTMLElement>("demo3SummaryExtractedCandidateCount").textContent = String(result.extractedCandidateCount);
byId<HTMLElement>("demo3SummaryRejectedCandidateCount").textContent = String(result.targetRejectedCandidateCount);
byId<HTMLElement>("demo3SummaryCandidateCount").textContent = String(result.candidateCount);
byId<HTMLElement>("demo3TargetText").textContent = `${result.resolvedDexCode ?? "custom"} / ${result.resolvedProgramId}`;
const targetEvent = result.request.targetEvent ?? "any";
byId<HTMLElement>("demo3TargetText").textContent = `${result.resolvedDexCode ?? "custom"} / program=${result.resolvedProgramId} / source=${result.resolvedSignatureSource}:${result.resolvedSignatureAddress} / target=${targetEvent}`;
byId<HTMLElement>("demo3UniqueSignatureText").textContent = result.uniqueBackfillSignatures.length === 0 ? "-" : result.uniqueBackfillSignatures.join(", ");
renderRejectedSummary(result);
renderOnchainCandidates(result.candidates);
}
function renderRejectedSummary(result: Demo3OnchainDexDiscoveryResult): void {
const body = byId<HTMLTableSectionElement>("demo3RejectedSummaryTableBody");
if (result.rejectedCandidateSummary.length === 0) {
body.innerHTML = '<tr><td colspan="5" class="text-body-secondary">No rejected candidate summary.</td></tr>';
return;
}
body.innerHTML = result.rejectedCandidateSummary.map((summary) => `
<tr>
<td>${escapeHtml(summary.candidateKind)}</td>
<td class="font-monospace" title="${escapeHtml(summary.instructionDataPrefix ?? "")}">${escapeHtml(shortText(summary.instructionDataPrefix, 16))}</td>
<td>${escapeHtml(summary.instructionName ?? "-")}</td>
<td>${escapeHtml(summary.rejectionReason)}</td>
<td>${summary.count}</td>
</tr>`).join("");
}
function renderOnchainCandidates(candidates: Demo3OnchainDexPairCandidate[]): void {
const body = byId<HTMLTableSectionElement>("demo3OnchainCandidateTableBody");
if (candidates.length === 0) {
body.innerHTML = '<tr><td colspan="11" class="text-body-secondary">No on-chain candidate.</td></tr>';
body.innerHTML = '<tr><td colspan="12" class="text-body-secondary">No on-chain candidate.</td></tr>';
return;
}
body.innerHTML = candidates.map((candidate) => {
@@ -225,6 +332,7 @@ function renderOnchainCandidates(candidates: Demo3OnchainDexPairCandidate[]): vo
<td>${candidate.slot ?? "-"}</td>
<td><span class="badge text-bg-info">${escapeHtml(candidate.candidateKind)}</span></td>
<td><span class="badge text-bg-${candidate.confidence === "high" ? "success" : candidate.confidence === "medium" ? "warning" : "secondary"}">${escapeHtml(candidate.confidence)}</span></td>
<td class="font-monospace" title="${escapeHtml(candidate.instructionDataPrefix ?? "")}">${escapeHtml(shortText(candidate.instructionDataPrefix, 14))}</td>
<td class="font-monospace" title="${escapeHtml(verifiedPool ?? "")}">${escapeHtml(shortText(verifiedPool, 14))}</td>
<td class="font-monospace" title="${escapeHtml(candidate.tokenAMint ?? "")}">${escapeHtml(shortText(candidate.tokenAMint, 14))}</td>
<td class="font-monospace" title="${escapeHtml(candidate.tokenBMint ?? "")}">${escapeHtml(shortText(candidate.tokenBMint, 14))}</td>
@@ -258,15 +366,22 @@ function renderLocalResult(result: Demo3LocalDexCorpusSearchResult): void {
async function discoverOnchain(): Promise<void> {
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 ?? ""}' role='${request.httpRole}'`);
appendLogLine(`on-chain discovery dex='${request.dexCode ?? ""}' program='${request.programId ?? ""}' source='${request.signatureSource ?? "program_id"}:${request.sourceAddress ?? ""}' target='${request.targetEvent ?? "any"}' excludeSwaps='${request.excludeSwaps}' role='${request.httpRole}'`);
try {
const payload = await invoke<Demo3OnchainDexDiscoveryPayload>("demo3_discover_onchain_dex_pairs", { request });
lastResultJson = payload.resultJson;
byId<HTMLTextAreaElement>("demo3JsonTextarea").value = payload.resultJson;
renderOnchainResult(payload.result);
setStatus("ok", "text-bg-success");
appendLogLine(`on-chain discovery completed: candidates='${payload.result.candidateCount}' signatures='${payload.result.fetchedSignatureCount}'`);
appendLogLine(`on-chain discovery completed: candidates='${payload.result.candidateCount}' unique='${payload.result.uniqueSignatureCount}' signatures='${payload.result.fetchedSignatureCount}' 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)}`);