v0.1.0-pre.062
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_execution_solana_core.html -->
|
||||
<!-- version: 10 -->
|
||||
<!-- version: 11 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<div class="d-flex flex-wrap align-items-center justify-content-between gap-2 mb-3">
|
||||
<h2 class="h5 mb-0">System Program</h2><span class="badge text-bg-primary">solana_native_classifier</span>
|
||||
<h2 class="h5 mb-0">System Program</h2><span class="badge text-bg-primary">solana.core</span>
|
||||
</div>
|
||||
<div class="mb-3"><label class="form-label" for="executionProfileSelect">Profil Devnet</label><select class="form-select" id="executionProfileSelect"></select>
|
||||
<div class="form-text" id="executionProfileHelp"></div>
|
||||
@@ -72,14 +72,14 @@
|
||||
<div class="col-12 col-xl-7">
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body">
|
||||
<h2 class="h5 mb-3">Résumé</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionSummaryOutput" readonly="" rows="14">{"status":"idle","message":"Aucun résultat."}</textarea>
|
||||
<h2 class="h5 mb-3">Résumé</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionSummaryOutput" readonly="" rows="14">{"title":"Résumé","status":"idle","message":"Aucun résultat."}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card shadow-sm border-0 mt-4">
|
||||
<div class="card-body">
|
||||
<h2 class="h5">Plan exact</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionPlanOutput" readonly="" rows="12">{"status":"idle","message":"Aucun plan."}</textarea>
|
||||
<h2 class="h5 mt-3">Simulation exacte</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionSimulationOutput" readonly="" rows="12">{"status":"idle","message":"Aucune simulation."}</textarea>
|
||||
<h2 class="h5 mt-3">Confirmation et replay</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionDiagnosticsOutput" readonly="" rows="12">{"status":"idle","message":"Aucun diagnostic."}</textarea>
|
||||
<h2 class="h5">Plan exact</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionPlanOutput" readonly="" rows="12">{"title":"Plan exact","status":"idle","message":"Aucun plan."}</textarea>
|
||||
<h2 class="h5 mt-3">Simulation exacte</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionSimulationOutput" readonly="" rows="12">{"title":"Simulation exacte","status":"idle","message":"Aucune simulation."}</textarea>
|
||||
<h2 class="h5 mt-3">Confirmation et replay</h2><textarea class="form-control font-monospace" data-json-viewer="true" id="executionDiagnosticsOutput" readonly="" rows="12">{"title":"Confirmation et replay","status":"idle","message":"Aucun diagnostic."}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: kb-app-demo-desktop/frontend/demo_execution_spl.html -->
|
||||
<!-- version: 14 -->
|
||||
<!-- version: 15 -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
|
||||
@@ -269,7 +269,7 @@
|
||||
</h2>
|
||||
<div class="accordion-collapse collapse" data-bs-parent="#executionDetailsAccordion" id="executionPlanCollapse">
|
||||
<div class="accordion-body">
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionPlanOutput" readonly="" rows="16">{"status":"idle","message":"Aucun plan."}</textarea>
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionPlanOutput" readonly="" rows="16">{"title":"Plan exact","status":"idle","message":"Aucun plan."}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -279,7 +279,7 @@
|
||||
</h2>
|
||||
<div class="accordion-collapse collapse" data-bs-parent="#executionDetailsAccordion" id="executionSimulationCollapse">
|
||||
<div class="accordion-body">
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionSimulationOutput" readonly="" rows="16">{"status":"idle","message":"Aucune simulation."}</textarea>
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionSimulationOutput" readonly="" rows="16">{"title":"Simulation exacte","status":"idle","message":"Aucune simulation."}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -289,7 +289,7 @@
|
||||
</h2>
|
||||
<div class="accordion-collapse collapse" data-bs-parent="#executionDetailsAccordion" id="executionDiagnosticsCollapse">
|
||||
<div class="accordion-body">
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionDiagnosticsOutput" readonly="" rows="16">{"status":"idle","message":"Aucun diagnostic."}</textarea>
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionDiagnosticsOutput" readonly="" rows="16">{"title":"Confirmation et replay","status":"idle","message":"Aucun diagnostic."}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -358,7 +358,7 @@
|
||||
</table>
|
||||
</div>
|
||||
<label class="form-label" for="tokenJournalDetailOutput">Détail JSON de la ligne sélectionnée</label>
|
||||
<textarea class="form-control font-monospace" id="tokenJournalDetailOutput" readonly="" rows="14">Aucun événement sélectionné.</textarea>
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="tokenJournalDetailOutput" readonly="" rows="14">{"title":"Journal métier SPL Token","status":"idle","message":"Aucun événement sélectionné."}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -399,7 +399,7 @@
|
||||
<input class="form-control" id="ataJournalLimitInput" max="500" min="1" type="number" value="100" />
|
||||
</div>
|
||||
</div>
|
||||
<textarea class="form-control font-monospace" id="ataJournalOutput" readonly="" rows="14">Aucune lecture.</textarea>
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="ataJournalOutput" readonly="" rows="14">{"title":"Journal lifecycle ATA","status":"idle","message":"Aucune lecture."}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -411,7 +411,7 @@
|
||||
<div class="card shadow-sm border-0 mt-4">
|
||||
<div class="card-body">
|
||||
<h2 class="h5 mb-3">Résumé</h2>
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionSummaryOutput" readonly="" rows="14">{"status":"idle","message":"Aucun résultat."}</textarea>
|
||||
<textarea class="form-control font-monospace" data-json-viewer="true" id="executionSummaryOutput" readonly="" rows="14">{"title":"Résumé","status":"idle","message":"Aucun résultat."}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card shadow-sm border-0 mt-4">
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
<hr class="dropdown-divider">
|
||||
</li>
|
||||
<li>
|
||||
<h6 class="dropdown-header">Exécution</h6>
|
||||
<h6 class="dropdown-header">Exécution Devnet</h6>
|
||||
</li>
|
||||
<li><a id="openDemoExecutionSolanaCoreLink" class="dropdown-item" href="#">Solana Core</a></li>
|
||||
<li><a id="openDemoExecutionSplLink" class="dropdown-item" href="#">SPL</a></li>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_execution_solana_core.ts
|
||||
// version: 7
|
||||
// version: 10
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import "simplebar";
|
||||
@@ -7,6 +7,7 @@ import ResizeObserver from "resize-observer-polyfill";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { frontendDebug, frontendError, frontendWarn, installFrontendConsoleBridge } from "./frontend_log";
|
||||
import type { DemoExecutionDevnetStoreReadinessPayload } from "./bindings/kb_app_demo_desktop/demo_execution_solana_core/DemoExecutionDevnetStoreReadinessPayload.ts";
|
||||
import type { DemoExecutionSolanaCoreGeneratedRecipientPayload } from "./bindings/kb_app_demo_desktop/demo_execution_solana_core/DemoExecutionSolanaCoreGeneratedRecipientPayload.ts";
|
||||
import type { DemoExecutionSolanaCoreOptionsPayload } from "./bindings/kb_app_demo_desktop/demo_execution_solana_core/DemoExecutionSolanaCoreOptionsPayload.ts";
|
||||
import type { DemoExecutionSolanaCoreProfileOption } from "./bindings/kb_app_demo_desktop/demo_execution_solana_core/DemoExecutionSolanaCoreProfileOption.ts";
|
||||
@@ -17,15 +18,20 @@ import type { DemoExecutionSolanaCoreSummaryPayload } from "./bindings/kb_app_de
|
||||
(window as Window & typeof globalThis & { ResizeObserver?: typeof ResizeObserver }).ResizeObserver = ResizeObserver;
|
||||
const logLines: string[] = [];
|
||||
let running = false;
|
||||
let profileStoreReady = false;
|
||||
let profileOptions: DemoExecutionSolanaCoreProfileOption[] = [];
|
||||
function element<T extends HTMLElement>(selector: string): T { const value=document.querySelector<T>(selector); if(!value){throw new Error(`Missing UI element: ${selector}`);} return value; }
|
||||
function integerValue(selector: string): number { const value=Number.parseInt(element<HTMLInputElement>(selector).value,10); if(!Number.isFinite(value)||value<0){throw new Error(`Valeur numérique invalide pour ${selector}`);} return value; }
|
||||
function selectedProfile(): DemoExecutionSolanaCoreProfileOption|null { const name=element<HTMLSelectElement>("#executionProfileSelect").value; return profileOptions.find(profile=>profile.name===name)??null; }
|
||||
function appendLog(payload: DemoExecutionSolanaCoreProgressPayload|{timestamp:string;level:string;stage:string;message:string;signature?:string|null}):void { const signature=payload.signature?` signature=${payload.signature}`:""; logLines.push(`${payload.timestamp} ${payload.level.toUpperCase()} [${payload.stage}] ${payload.message}${signature}`); const output=element<HTMLTextAreaElement>("#executionLogOutput"); output.value=logLines.join("\n"); output.scrollTop=output.scrollHeight; }
|
||||
function setRunning(value:boolean):void { running=value; const profile=selectedProfile(); element<HTMLButtonElement>("#simulateExecutionButton").disabled=value||!profile; element<HTMLButtonElement>("#submitExecutionButton").disabled=value||!profile||!profile.sendEnabled; element<HTMLButtonElement>("#generateRecipientButton").disabled=value; element<HTMLButtonElement>("#cancelExecutionButton").disabled=!value; const badge=element<HTMLElement>("#executionStatusBadge"); badge.textContent=value?"Exécution en cours":"Prêt"; badge.className=value?"badge text-bg-warning":"badge text-bg-success"; }
|
||||
function setRunning(value:boolean):void { running=value; const profile=selectedProfile(); element<HTMLButtonElement>("#simulateExecutionButton").disabled=value||!profile||!profileStoreReady; element<HTMLButtonElement>("#submitExecutionButton").disabled=value||!profile||!profileStoreReady||!profile.sendEnabled; element<HTMLButtonElement>("#generateRecipientButton").disabled=value; element<HTMLButtonElement>("#cancelExecutionButton").disabled=!value; const badge=element<HTMLElement>("#executionStatusBadge"); badge.textContent=value?"Exécution en cours":"Prêt"; badge.className=value?"badge text-bg-warning":"badge text-bg-success"; }
|
||||
function updateProfileHelp():void { const profile=selectedProfile(); const help=element<HTMLElement>("#executionProfileHelp"); if(!profile){help.textContent="Aucun profil Devnet compatible.";return;} help.textContent=`wallet=${profile.walletAlias}, spendMax=${profile.maxSpendLamports}, airdropMax=${profile.maxAirdropLamports}, send=${profile.sendEnabled?"enabled":"disabled"}`; element<HTMLInputElement>("#executionAirdropInput").max=String(profile.maxAirdropLamports); element<HTMLInputElement>("#executionLamportsInput").max=String(profile.maxSpendLamports); setRunning(running); }
|
||||
function buildRequest(submit:boolean):DemoExecutionSolanaCoreRequest { const recipient=element<HTMLInputElement>("#executionRecipientInput").value.trim(); if(recipient.length===0){throw new Error("Le destinataire est obligatoire.");} return {profileName:element<HTMLSelectElement>("#executionProfileSelect").value,recipient,lamports:integerValue("#executionLamportsInput"),airdropLamports:integerValue("#executionAirdropInput"),submit,operatorConfirmed:element<HTMLInputElement>("#executionOperatorConfirmedInput").checked,forcePostValidationReplay:element<HTMLInputElement>("#executionForceReplayInput").checked,materializeAfterDecode:element<HTMLInputElement>("#executionMaterializeInput").checked}; }
|
||||
function displaySummary(summary:DemoExecutionSolanaCoreSummaryPayload):void { element<HTMLTextAreaElement>("#executionSummaryOutput").value=JSON.stringify(summary,null,2); element<HTMLTextAreaElement>("#executionPlanOutput").value=summary.planJson; element<HTMLTextAreaElement>("#executionSimulationOutput").value=summary.simulationJson; element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value=summary.diagnosticsJson; }
|
||||
async function execute(submit:boolean):Promise<void>{if(running){return;}try{const request=buildRequest(submit);if(submit&&!request.operatorConfirmed){frontendWarn("kb-app-demo-desktop.frontend.demo_execution_solana_core","Submission blocked: operator confirmation missing");return;}setRunning(true);const summary=await invoke<DemoExecutionSolanaCoreSummaryPayload>("demo_execution_solana_core_execute",{request});displaySummary(summary);}catch(caughtError){const message=caughtError instanceof Error?caughtError.message:String(caughtError);frontendError("kb-app-demo-desktop.frontend.demo_execution_solana_core",`Execution failed: ${message}`);}finally{setRunning(false);}}
|
||||
async function loadOptions():Promise<void>{const options=await invoke<DemoExecutionSolanaCoreOptionsPayload>("demo_execution_solana_core_options");profileOptions=options.profiles;const select=element<HTMLSelectElement>("#executionProfileSelect");select.replaceChildren();for(const profile of profileOptions){const option=document.createElement("option");option.value=profile.name;option.textContent=profile.name;option.selected=profile.name===options.defaultProfileName;select.append(option);}element<HTMLInputElement>("#executionLamportsInput").value=String(options.defaultTransferLamports);updateProfileHelp();setRunning(options.running);}
|
||||
document.addEventListener("DOMContentLoaded",async()=>{installFrontendConsoleBridge("kb-app-demo-desktop.frontend.demo_execution_solana_core");frontendDebug("kb-app-demo-desktop.frontend.demo_execution_solana_core","Solana Core execution window loaded");await listen<DemoExecutionSolanaCoreProgressPayload>("demo-execution-solana-core-progress",event=>appendLog(event.payload));element<HTMLSelectElement>("#executionProfileSelect").addEventListener("change",updateProfileHelp);element<HTMLButtonElement>("#generateRecipientButton").addEventListener("click",async()=>{const payload=await invoke<DemoExecutionSolanaCoreGeneratedRecipientPayload>("demo_execution_solana_core_generate_recipient");element<HTMLInputElement>("#executionRecipientInput").value=payload.publicKey;});element<HTMLButtonElement>("#simulateExecutionButton").addEventListener("click",()=>void execute(false));element<HTMLButtonElement>("#submitExecutionButton").addEventListener("click",()=>void execute(true));element<HTMLButtonElement>("#cancelExecutionButton").addEventListener("click",()=>void invoke("demo_execution_solana_core_cancel"));element<HTMLTextAreaElement>("#executionLogOutput").addEventListener("app-log-clear",()=>{logLines.length=0;});try{await loadOptions();}catch(caughtError){const message=caughtError instanceof Error?caughtError.message:String(caughtError);frontendError("kb-app-demo-desktop.frontend.demo_execution_solana_core",`Options loading failed: ${message}`);}});
|
||||
function titledJson(title:string,value:string):string { try { const parsed:unknown=JSON.parse(value); if(parsed!==null&&typeof parsed==="object"&&!Array.isArray(parsed)){return JSON.stringify({title,...parsed},null,2);} return JSON.stringify({title,value:parsed},null,2); } catch { return JSON.stringify({title,status:"invalid_json",raw:value},null,2); } }
|
||||
function displaySummary(summary:DemoExecutionSolanaCoreSummaryPayload):void { element<HTMLTextAreaElement>("#executionSummaryOutput").value=JSON.stringify({title:"Résumé",...summary},null,2); element<HTMLTextAreaElement>("#executionPlanOutput").value=titledJson("Plan exact",summary.planJson); element<HTMLTextAreaElement>("#executionSimulationOutput").value=titledJson("Simulation exacte",summary.simulationJson); element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value=titledJson("Confirmation et replay",summary.diagnosticsJson); }
|
||||
function displayExecutionFailure(message:string,submit:boolean):void { element<HTMLTextAreaElement>("#executionSummaryOutput").value=JSON.stringify({title:"Résumé",status:"error",message},null,2); element<HTMLTextAreaElement>("#executionPlanOutput").value=JSON.stringify({title:"Plan exact",status:"unavailable",reason:"preflight_failed",message:"Aucun plan exécutable n’a été produit.",error:message},null,2); element<HTMLTextAreaElement>("#executionSimulationOutput").value=JSON.stringify({title:"Simulation exacte",status:"not_started",reason:"preflight_failed",message:"La simulation n’a pas été lancée.",error:message},null,2); element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value=JSON.stringify({title:"Confirmation et replay",status:"not_started",reason:"execution_failed_before_submission",message:submit?"La signature, l’envoi, la confirmation et le replay n’ont pas été exécutés.":"La confirmation et le replay ne s’appliquent pas à cette simulation refusée.",error:message},null,2); appendLog({timestamp:new Date().toISOString(),level:"error",stage:"failed",message}); }
|
||||
async function execute(submit:boolean):Promise<void>{if(running){return;}try{const request=buildRequest(submit);if(submit&&!request.operatorConfirmed){const message="La confirmation opérateur explicite est obligatoire avant signature et envoi.";displayExecutionFailure(message,submit);frontendWarn("kb-app-demo-desktop.frontend.demo_execution_solana_core","Submission blocked: operator confirmation missing");return;}setRunning(true);const summary=await invoke<DemoExecutionSolanaCoreSummaryPayload>("demo_execution_solana_core_execute",{request});displaySummary(summary);}catch(caughtError){const message=caughtError instanceof Error?caughtError.message:String(caughtError);displayExecutionFailure(message,submit);frontendError("kb-app-demo-desktop.frontend.demo_execution_solana_core",`Execution failed: ${message}`);}finally{setRunning(false);}}
|
||||
|
||||
async function prepareSelectedProfile():Promise<void>{const profile=selectedProfile();profileStoreReady=false;setRunning(running);if(!profile){return;}appendLog({timestamp:new Date().toISOString(),level:"info",stage:"store_prepare",message:`Vérification PostgreSQL du profil ${profile.name}.`});try{const readiness=await invoke<DemoExecutionDevnetStoreReadinessPayload>("demo_execution_devnet_prepare_profile",{profileName:profile.name});profileStoreReady=true;appendLog({timestamp:new Date().toISOString(),level:"info",stage:"store_ready",message:`PostgreSQL prêt: ${readiness.existingTablesAfter}/${readiness.expectedTables} tables, créées=${readiness.createdTables}, autoInit=${readiness.autoInitializeSchema}.`});}catch(caughtError){const message=caughtError instanceof Error?caughtError.message:String(caughtError);frontendError("kb-app-demo-desktop.frontend.demo_execution_solana_core",`Devnet store preparation failed: ${message}`);}finally{setRunning(running);}}
|
||||
async function loadOptions():Promise<void>{const options=await invoke<DemoExecutionSolanaCoreOptionsPayload>("demo_execution_solana_core_options");profileOptions=options.profiles;const select=element<HTMLSelectElement>("#executionProfileSelect");select.replaceChildren();for(const profile of profileOptions){const option=document.createElement("option");option.value=profile.name;option.textContent=profile.name;option.selected=profile.name===options.defaultProfileName;select.append(option);}element<HTMLInputElement>("#executionLamportsInput").value=String(options.defaultTransferLamports);updateProfileHelp();setRunning(options.running);await prepareSelectedProfile();}
|
||||
document.addEventListener("DOMContentLoaded",async()=>{installFrontendConsoleBridge("kb-app-demo-desktop.frontend.demo_execution_solana_core");frontendDebug("kb-app-demo-desktop.frontend.demo_execution_solana_core","Solana Core execution window loaded");await listen<DemoExecutionSolanaCoreProgressPayload>("demo-execution-solana-core-progress",event=>appendLog(event.payload));element<HTMLSelectElement>("#executionProfileSelect").addEventListener("change",()=>{updateProfileHelp();void prepareSelectedProfile();});element<HTMLButtonElement>("#generateRecipientButton").addEventListener("click",async()=>{const payload=await invoke<DemoExecutionSolanaCoreGeneratedRecipientPayload>("demo_execution_solana_core_generate_recipient");element<HTMLInputElement>("#executionRecipientInput").value=payload.publicKey;});element<HTMLButtonElement>("#simulateExecutionButton").addEventListener("click",()=>void execute(false));element<HTMLButtonElement>("#submitExecutionButton").addEventListener("click",()=>void execute(true));element<HTMLButtonElement>("#cancelExecutionButton").addEventListener("click",()=>void invoke("demo_execution_solana_core_cancel"));element<HTMLTextAreaElement>("#executionLogOutput").addEventListener("app-log-clear",()=>{logLines.length=0;});try{await loadOptions();}catch(caughtError){const message=caughtError instanceof Error?caughtError.message:String(caughtError);frontendError("kb-app-demo-desktop.frontend.demo_execution_solana_core",`Options loading failed: ${message}`);}});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/frontend/ts/demo_execution_spl.ts
|
||||
// version: 4
|
||||
// version: 9
|
||||
|
||||
import * as bootstrap from "bootstrap";
|
||||
import "simplebar";
|
||||
@@ -7,6 +7,7 @@ import ResizeObserver from "resize-observer-polyfill";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { frontendDebug, frontendError, frontendWarn, installFrontendConsoleBridge } from "./frontend_log";
|
||||
import type { DemoExecutionDevnetStoreReadinessPayload } from "./bindings/kb_app_demo_desktop/demo_execution_solana_core/DemoExecutionDevnetStoreReadinessPayload.ts";
|
||||
import type { DemoExecutionSolanaCoreGeneratedRecipientPayload } from "./bindings/kb_app_demo_desktop/demo_execution_solana_core/DemoExecutionSolanaCoreGeneratedRecipientPayload.ts";
|
||||
import type { DemoExecutionSolanaCoreOptionsPayload } from "./bindings/kb_app_demo_desktop/demo_execution_solana_core/DemoExecutionSolanaCoreOptionsPayload.ts";
|
||||
import type { DemoExecutionSolanaCoreProfileOption } from "./bindings/kb_app_demo_desktop/demo_execution_solana_core/DemoExecutionSolanaCoreProfileOption.ts";
|
||||
@@ -36,6 +37,7 @@ import type { DemoSplToken2022FixturePayload } from "./bindings/kb_app_demo_desk
|
||||
const logLines: string[] = [];
|
||||
const maximumLogLines = 1200;
|
||||
let running = false;
|
||||
let profileStoreReady = false;
|
||||
let profileOptions: DemoExecutionSolanaCoreProfileOption[] = [];
|
||||
let token_2022Fixture: DemoSplToken2022FixturePayload | null = null;
|
||||
|
||||
@@ -55,6 +57,61 @@ function integerValue(selector: string): number {
|
||||
return value;
|
||||
}
|
||||
|
||||
function parsedJson(value: string): unknown {
|
||||
try {
|
||||
return JSON.parse(value) as unknown;
|
||||
} catch {
|
||||
return { raw: value };
|
||||
}
|
||||
}
|
||||
|
||||
function writePanel(selector: string, title: string, payload: Record<string, unknown>): void {
|
||||
element<HTMLTextAreaElement>(selector).value = JSON.stringify({ title, ...payload }, null, 2);
|
||||
}
|
||||
|
||||
function writeJsonPanel(selector: string, title: string, value: string): void {
|
||||
const parsed = parsedJson(value);
|
||||
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
||||
writePanel(selector, title, parsed as Record<string, unknown>);
|
||||
return;
|
||||
}
|
||||
writePanel(selector, title, { value: parsed });
|
||||
}
|
||||
|
||||
function writePlanPanel(preflightJson: string | null, planJson: string): void {
|
||||
const payload: Record<string, unknown> = { plan: parsedJson(planJson) };
|
||||
if (preflightJson !== null) {
|
||||
payload.preflight = parsedJson(preflightJson);
|
||||
}
|
||||
writePanel("#executionPlanOutput", "Plan exact", payload);
|
||||
}
|
||||
|
||||
function writeExecutionState(status: string, message: string, error: string | null = null): void {
|
||||
const summary: Record<string, unknown> = { status, message };
|
||||
if (error !== null) {
|
||||
summary.error = error;
|
||||
}
|
||||
writePanel("#executionSummaryOutput", "Résumé", summary);
|
||||
writePanel("#executionPlanOutput", "Plan exact", {
|
||||
status: status === "running" ? "pending" : "unavailable",
|
||||
reason: status,
|
||||
message: status === "running" ? "Préparation du plan en cours." : "Aucun plan exécutable n’a été produit.",
|
||||
...(error === null ? {} : { error }),
|
||||
});
|
||||
writePanel("#executionSimulationOutput", "Simulation exacte", {
|
||||
status: status === "running" ? "pending" : "not_started",
|
||||
reason: status,
|
||||
message: status === "running" ? "Simulation en attente du plan exact." : "La simulation n’a pas été lancée.",
|
||||
...(error === null ? {} : { error }),
|
||||
});
|
||||
writePanel("#executionDiagnosticsOutput", "Confirmation et replay", {
|
||||
status: status === "running" ? "pending" : "not_started",
|
||||
reason: status,
|
||||
message: status === "running" ? "En attente de la simulation et d’un éventuel envoi." : "La confirmation et le replay n’ont pas été exécutés.",
|
||||
...(error === null ? {} : { error }),
|
||||
});
|
||||
}
|
||||
|
||||
function appendLog(payload: DemoExecutionSolanaCoreProgressPayload | { timestamp: string; level: string; stage: string; message: string; signature?: string | null }): void {
|
||||
const signature = payload.signature ? ` signature=${payload.signature}` : "";
|
||||
logLines.push(`${payload.timestamp} ${payload.level.toUpperCase()} [${payload.stage}] ${payload.message}${signature}`);
|
||||
@@ -69,18 +126,19 @@ function appendLog(payload: DemoExecutionSolanaCoreProgressPayload | { timestamp
|
||||
function setRunning(value: boolean): void {
|
||||
running = value;
|
||||
const profile = selectedProfile();
|
||||
element<HTMLButtonElement>("#simulateExecutionButton").disabled = value || !profile;
|
||||
element<HTMLButtonElement>("#submitExecutionButton").disabled = value || !profile || !profile.sendEnabled;
|
||||
element<HTMLButtonElement>("#simulateMemoButton").disabled = value || !profile;
|
||||
element<HTMLButtonElement>("#submitMemoButton").disabled = value || !profile || !profile.sendEnabled;
|
||||
element<HTMLButtonElement>("#simulateTokenButton").disabled = value || !profile;
|
||||
element<HTMLButtonElement>("#submitTokenButton").disabled = value || !profile || !profile.sendEnabled;
|
||||
element<HTMLButtonElement>("#deriveAtaButton").disabled = value || !profile;
|
||||
element<HTMLButtonElement>("#simulateAtaButton").disabled = value || !profile;
|
||||
element<HTMLButtonElement>("#submitAtaButton").disabled = value || !profile || !profile.sendEnabled;
|
||||
element<HTMLButtonElement>("#simulateToken2022Button").disabled = value || !profile;
|
||||
element<HTMLButtonElement>("#submitToken2022Button").disabled = value || !profile || !profile.sendEnabled;
|
||||
element<HTMLButtonElement>("#loadToken2022FixtureButton").disabled = value || !profile;
|
||||
const unavailable = value || !profile || !profileStoreReady;
|
||||
element<HTMLButtonElement>("#simulateExecutionButton").disabled = unavailable;
|
||||
element<HTMLButtonElement>("#submitExecutionButton").disabled = unavailable || !profile?.sendEnabled;
|
||||
element<HTMLButtonElement>("#simulateMemoButton").disabled = unavailable;
|
||||
element<HTMLButtonElement>("#submitMemoButton").disabled = unavailable || !profile?.sendEnabled;
|
||||
element<HTMLButtonElement>("#simulateTokenButton").disabled = unavailable;
|
||||
element<HTMLButtonElement>("#submitTokenButton").disabled = unavailable || !profile?.sendEnabled;
|
||||
element<HTMLButtonElement>("#deriveAtaButton").disabled = unavailable;
|
||||
element<HTMLButtonElement>("#simulateAtaButton").disabled = unavailable;
|
||||
element<HTMLButtonElement>("#submitAtaButton").disabled = unavailable || !profile?.sendEnabled;
|
||||
element<HTMLButtonElement>("#simulateToken2022Button").disabled = unavailable;
|
||||
element<HTMLButtonElement>("#submitToken2022Button").disabled = unavailable || !profile?.sendEnabled;
|
||||
element<HTMLButtonElement>("#loadToken2022FixtureButton").disabled = unavailable;
|
||||
element<HTMLButtonElement>("#generateRecipientButton").disabled = value;
|
||||
element<HTMLButtonElement>("#cancelExecutionButton").disabled = !value;
|
||||
const badge = element<HTMLElement>("#executionStatusBadge");
|
||||
@@ -146,10 +204,10 @@ function displaySummary(summary: DemoExecutionSolanaCoreSummaryPayload): void {
|
||||
decodeCompleted: summary.decodeCompleted,
|
||||
decodeFailedInputs: summary.decodeFailedInputs,
|
||||
};
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify(concise, null, 2);
|
||||
element<HTMLTextAreaElement>("#executionPlanOutput").value = summary.planJson;
|
||||
element<HTMLTextAreaElement>("#executionSimulationOutput").value = summary.simulationJson;
|
||||
element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value = summary.diagnosticsJson;
|
||||
writePanel("#executionSummaryOutput", "Résumé", concise);
|
||||
writePlanPanel(null, summary.planJson);
|
||||
writeJsonPanel("#executionSimulationOutput", "Simulation exacte", summary.simulationJson);
|
||||
writeJsonPanel("#executionDiagnosticsOutput", "Confirmation et replay", summary.diagnosticsJson);
|
||||
}
|
||||
|
||||
function buildMemoRequest(submit: boolean): DemoExecutionMemoRequest {
|
||||
@@ -165,7 +223,7 @@ function buildMemoRequest(submit: boolean): DemoExecutionMemoRequest {
|
||||
|
||||
function displayMemoSummary(summary: DemoExecutionMemoSummaryPayload): void {
|
||||
const concise = {
|
||||
operation: "spl_memo_v4.add_memo",
|
||||
operation: "spl.memo.v4.add_memo",
|
||||
profileName: summary.profileName,
|
||||
cluster: summary.cluster,
|
||||
genesisHash: summary.genesisHash,
|
||||
@@ -183,10 +241,10 @@ function displayMemoSummary(summary: DemoExecutionMemoSummaryPayload): void {
|
||||
annotationCount: summary.annotationCount,
|
||||
idempotenceValidated: summary.idempotenceValidated,
|
||||
};
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify(concise, null, 2);
|
||||
element<HTMLTextAreaElement>("#executionPlanOutput").value = summary.planJson;
|
||||
element<HTMLTextAreaElement>("#executionSimulationOutput").value = summary.simulationJson;
|
||||
element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value = summary.diagnosticsJson;
|
||||
writePanel("#executionSummaryOutput", "Résumé", concise);
|
||||
writePlanPanel(null, summary.planJson);
|
||||
writeJsonPanel("#executionSimulationOutput", "Simulation exacte", summary.simulationJson);
|
||||
writeJsonPanel("#executionDiagnosticsOutput", "Confirmation et replay", summary.diagnosticsJson);
|
||||
}
|
||||
|
||||
function requiredText(selector: string, label: string): string {
|
||||
@@ -247,10 +305,10 @@ function displayTokenSummary(summary: DemoExecutionSplTokenSummaryPayload): void
|
||||
materializationCount: summary.materializationCount,
|
||||
idempotenceValidated: summary.idempotenceValidated,
|
||||
};
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify(concise, null, 2);
|
||||
element<HTMLTextAreaElement>("#executionPlanOutput").value = `PRÉFLIGHT\n${summary.readinessJson}\n\nPLAN\n${summary.planJson}`;
|
||||
element<HTMLTextAreaElement>("#executionSimulationOutput").value = summary.simulationJson;
|
||||
element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value = summary.diagnosticsJson;
|
||||
writePanel("#executionSummaryOutput", "Résumé", concise);
|
||||
writePlanPanel(summary.readinessJson, summary.planJson);
|
||||
writeJsonPanel("#executionSimulationOutput", "Simulation exacte", summary.simulationJson);
|
||||
writeJsonPanel("#executionDiagnosticsOutput", "Confirmation et replay", summary.diagnosticsJson);
|
||||
}
|
||||
|
||||
function ataDerivationRequest(): DemoSplAtaDerivationRequest {
|
||||
@@ -272,7 +330,7 @@ async function deriveAta(): Promise<DemoSplAtaDerivationPayload> {
|
||||
}
|
||||
|
||||
function displayAtaSummary(summary: DemoExecutionSplAtaSummaryPayload): void {
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({
|
||||
writePanel("#executionSummaryOutput", "Résumé", {
|
||||
operation: summary.operation,
|
||||
profileName: summary.profileName,
|
||||
walletPublicKey: summary.walletPublicKey,
|
||||
@@ -287,10 +345,10 @@ function displayAtaSummary(summary: DemoExecutionSplAtaSummaryPayload): void {
|
||||
confirmationStatus: summary.confirmationStatus,
|
||||
materializationCount: summary.materializationCount,
|
||||
idempotenceValidated: summary.idempotenceValidated,
|
||||
}, null, 2);
|
||||
element<HTMLTextAreaElement>("#executionPlanOutput").value = `PRÉFLIGHT\n${summary.readinessJson}\n\nPLAN\n${summary.planJson}`;
|
||||
element<HTMLTextAreaElement>("#executionSimulationOutput").value = summary.simulationJson;
|
||||
element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value = summary.diagnosticsJson;
|
||||
});
|
||||
writePlanPanel(summary.readinessJson, summary.planJson);
|
||||
writeJsonPanel("#executionSimulationOutput", "Simulation exacte", summary.simulationJson);
|
||||
writeJsonPanel("#executionDiagnosticsOutput", "Confirmation et replay", summary.diagnosticsJson);
|
||||
}
|
||||
|
||||
async function executeAta(submit: boolean): Promise<void> {
|
||||
@@ -305,6 +363,7 @@ async function executeAta(submit: boolean): Promise<void> {
|
||||
stage: "ata_validation",
|
||||
message,
|
||||
});
|
||||
writeExecutionState("error", message, message);
|
||||
frontendError("kb-app-demo-desktop.frontend.execution_spl", message);
|
||||
return;
|
||||
}
|
||||
@@ -321,6 +380,7 @@ async function executeAta(submit: boolean): Promise<void> {
|
||||
forcePostValidationReplay: element<HTMLInputElement>("#executionForceReplayInput").checked,
|
||||
};
|
||||
setRunning(true);
|
||||
writeExecutionState("running", "Préflight et exécution SPL ATA en cours.");
|
||||
appendLog({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: "info",
|
||||
@@ -344,6 +404,7 @@ async function executeAta(submit: boolean): Promise<void> {
|
||||
}
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
writeExecutionState("error", message, message);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "ata_failed", message });
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_execution_spl", `ATA execution failed: ${message}`);
|
||||
} finally {
|
||||
@@ -367,13 +428,23 @@ async function loadAtaJournal(): Promise<void> {
|
||||
button.disabled = true;
|
||||
try {
|
||||
const rows = await invoke<DemoSplAtaJournalRow[]>("demo_spl_ata_journal", { request: ataJournalRequest() });
|
||||
element<HTMLTextAreaElement>("#ataJournalOutput").value = JSON.stringify(rows.map(row => ({
|
||||
...row,
|
||||
payloadJson: JSON.parse(row.payloadJson) as unknown,
|
||||
})), null, 2);
|
||||
element<HTMLTextAreaElement>("#ataJournalOutput").value = JSON.stringify({
|
||||
title: "Journal lifecycle ATA",
|
||||
status: "success",
|
||||
count: rows.length,
|
||||
rows: rows.map(row => ({
|
||||
...row,
|
||||
payloadJson: parsedJson(row.payloadJson),
|
||||
})),
|
||||
}, null, 2);
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
element<HTMLTextAreaElement>("#ataJournalOutput").value = JSON.stringify({ error: message }, null, 2);
|
||||
element<HTMLTextAreaElement>("#ataJournalOutput").value = JSON.stringify({
|
||||
title: "Journal lifecycle ATA",
|
||||
status: "error",
|
||||
message,
|
||||
error: message,
|
||||
}, null, 2);
|
||||
} finally {
|
||||
button.disabled = false;
|
||||
}
|
||||
@@ -387,7 +458,7 @@ async function execute(submit: boolean): Promise<void> {
|
||||
const request = buildRequest(submit);
|
||||
if (submit && !request.operatorConfirmed) {
|
||||
const message = "La confirmation opérateur doit être cochée avant signature et envoi.";
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({ warning: message }, null, 2);
|
||||
writeExecutionState("warning", message);
|
||||
appendLog({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: "warn",
|
||||
@@ -398,7 +469,7 @@ async function execute(submit: boolean): Promise<void> {
|
||||
return;
|
||||
}
|
||||
setRunning(true);
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = "Exécution en cours...";
|
||||
writeExecutionState("running", "Exécution Solana Core en cours.");
|
||||
appendLog({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: "info",
|
||||
@@ -416,7 +487,7 @@ async function execute(submit: boolean): Promise<void> {
|
||||
});
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({ error: message }, null, 2);
|
||||
writeExecutionState("error", message, message);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "failed", message });
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_execution_spl", `Execution failed: ${message}`);
|
||||
} finally {
|
||||
@@ -432,12 +503,13 @@ async function executeMemo(submit: boolean): Promise<void> {
|
||||
const request = buildMemoRequest(submit);
|
||||
if (submit && !request.operatorConfirmed) {
|
||||
const message = "La confirmation opérateur doit être cochée avant signature et envoi du Memo.";
|
||||
writeExecutionState("warning", message);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "warn", stage: "memo_policy", message });
|
||||
frontendWarn("kb-app-demo-desktop.frontend.demo_execution_spl", `Memo execution blocked by policy: ${message}`);
|
||||
return;
|
||||
}
|
||||
setRunning(true);
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = "Exécution Memo en cours...";
|
||||
writeExecutionState("running", "Exécution Memo v4 en cours.");
|
||||
appendLog({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: "info",
|
||||
@@ -455,7 +527,7 @@ async function executeMemo(submit: boolean): Promise<void> {
|
||||
});
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({ error: message }, null, 2);
|
||||
writeExecutionState("error", message, message);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "memo_failed", message });
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_execution_spl", `Memo execution failed: ${message}`);
|
||||
} finally {
|
||||
@@ -471,12 +543,13 @@ async function executeToken(submit: boolean): Promise<void> {
|
||||
const request = buildTokenRequest(submit);
|
||||
if (submit && !request.operatorConfirmed) {
|
||||
const message = "La confirmation opérateur doit être cochée avant signature et envoi Token.";
|
||||
writeExecutionState("warning", message);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "warn", stage: "spl_token_policy", message });
|
||||
frontendWarn("kb-app-demo-desktop.frontend.demo_execution_spl", `Token execution blocked by policy: ${message}`);
|
||||
return;
|
||||
}
|
||||
setRunning(true);
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = "Préflight et exécution SPL Token en cours...";
|
||||
writeExecutionState("running", "Préflight et exécution SPL Token en cours.");
|
||||
appendLog({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: "info",
|
||||
@@ -498,7 +571,7 @@ async function executeToken(submit: boolean): Promise<void> {
|
||||
}
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({ error: message }, null, 2);
|
||||
writeExecutionState("error", message, message);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "spl_token_failed", message });
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_execution_spl", `Token execution failed: ${message}`);
|
||||
} finally {
|
||||
@@ -529,7 +602,11 @@ function renderTokenJournal(rows: DemoSplTokenJournalRow[]): void {
|
||||
cell.textContent = "Aucun événement correspondant.";
|
||||
row.append(cell);
|
||||
body.append(row);
|
||||
element<HTMLTextAreaElement>("#tokenJournalDetailOutput").value = "Aucun événement sélectionné.";
|
||||
element<HTMLTextAreaElement>("#tokenJournalDetailOutput").value = JSON.stringify({
|
||||
title: "Journal métier SPL Token",
|
||||
status: "empty",
|
||||
message: "Aucun événement sélectionné.",
|
||||
}, null, 2);
|
||||
return;
|
||||
}
|
||||
for (const item of rows) {
|
||||
@@ -550,7 +627,14 @@ function renderTokenJournal(rows: DemoSplTokenJournalRow[]): void {
|
||||
}
|
||||
row.title = item.signature;
|
||||
const select = (): void => {
|
||||
element<HTMLTextAreaElement>("#tokenJournalDetailOutput").value = item.payloadJson;
|
||||
element<HTMLTextAreaElement>("#tokenJournalDetailOutput").value = JSON.stringify({
|
||||
title: "Journal métier SPL Token",
|
||||
status: "success",
|
||||
row: {
|
||||
...item,
|
||||
payloadJson: parsedJson(item.payloadJson),
|
||||
},
|
||||
}, null, 2);
|
||||
};
|
||||
row.addEventListener("click", select);
|
||||
row.addEventListener("keydown", event => {
|
||||
@@ -561,22 +645,32 @@ function renderTokenJournal(rows: DemoSplTokenJournalRow[]): void {
|
||||
});
|
||||
body.append(row);
|
||||
}
|
||||
element<HTMLTextAreaElement>("#tokenJournalDetailOutput").value = rows[0].payloadJson;
|
||||
element<HTMLTextAreaElement>("#tokenJournalDetailOutput").value = JSON.stringify({
|
||||
title: "Journal métier SPL Token",
|
||||
status: "success",
|
||||
row: {
|
||||
...rows[0],
|
||||
payloadJson: parsedJson(rows[0].payloadJson),
|
||||
},
|
||||
}, null, 2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function token_2022ScenarioAmount(fixture: DemoSplToken2022FixturePayload, scenarioId: string): string {
|
||||
if (scenarioId === "token_2022_mint_to_checked") {
|
||||
return "1";
|
||||
return fixture.mintAmountRaw;
|
||||
}
|
||||
if (scenarioId === "token_2022_transfer_checked") {
|
||||
return fixture.transferAmountRaw;
|
||||
}
|
||||
if (scenarioId === "token_2022_approve_checked") {
|
||||
return "2";
|
||||
return fixture.approveAmountRaw;
|
||||
}
|
||||
if (scenarioId === "token_2022_burn_checked") {
|
||||
return "1";
|
||||
return fixture.burnAmountRaw;
|
||||
}
|
||||
return fixture.defaultAmountRaw;
|
||||
return "0";
|
||||
}
|
||||
|
||||
function applyToken2022Fixture(): void {
|
||||
@@ -666,7 +760,7 @@ function buildToken2022Request(submit: boolean): DemoExecutionSplToken2022Reques
|
||||
}
|
||||
|
||||
function displayToken2022Summary(summary: DemoExecutionSplToken2022SummaryPayload): void {
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({
|
||||
writePanel("#executionSummaryOutput", "Résumé", {
|
||||
scenarioId: summary.scenarioId,
|
||||
operation: summary.operation,
|
||||
profileName: summary.profileName,
|
||||
@@ -684,10 +778,10 @@ function displayToken2022Summary(summary: DemoExecutionSplToken2022SummaryPayloa
|
||||
decodeReplayed: summary.decodeReplayed,
|
||||
materializationCount: summary.materializationCount,
|
||||
idempotenceValidated: summary.idempotenceValidated,
|
||||
}, null, 2);
|
||||
element<HTMLTextAreaElement>("#executionPlanOutput").value = `PRÉFLIGHT\n${summary.preflightJson}\n\nPLAN\n${summary.planJson}`;
|
||||
element<HTMLTextAreaElement>("#executionSimulationOutput").value = summary.simulationJson;
|
||||
element<HTMLTextAreaElement>("#executionDiagnosticsOutput").value = summary.diagnosticsJson;
|
||||
});
|
||||
writePlanPanel(summary.preflightJson, summary.planJson);
|
||||
writeJsonPanel("#executionSimulationOutput", "Simulation exacte", summary.simulationJson);
|
||||
writeJsonPanel("#executionDiagnosticsOutput", "Confirmation et replay", summary.diagnosticsJson);
|
||||
}
|
||||
|
||||
async function executeToken2022(submit: boolean): Promise<void> {
|
||||
@@ -699,17 +793,18 @@ async function executeToken2022(submit: boolean): Promise<void> {
|
||||
request = buildToken2022Request(submit);
|
||||
if (submit && !request.operatorConfirmed) {
|
||||
const message = "La confirmation opérateur est obligatoire avant signature Token-2022.";
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({ warning: message }, null, 2);
|
||||
writeExecutionState("warning", message);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "token_2022_failed", message });
|
||||
return;
|
||||
}
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
writeExecutionState("error", message, message);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "token_2022_failed", message });
|
||||
return;
|
||||
}
|
||||
setRunning(true);
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = "Préflight et exécution Token-2022 en cours...";
|
||||
writeExecutionState("running", "Préflight et exécution Token-2022 en cours.");
|
||||
appendLog({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: "info",
|
||||
@@ -728,7 +823,7 @@ async function executeToken2022(submit: boolean): Promise<void> {
|
||||
});
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
element<HTMLTextAreaElement>("#executionSummaryOutput").value = JSON.stringify({ error: message }, null, 2);
|
||||
writeExecutionState("error", message, message);
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "error", stage: "token_2022_failed", message });
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_execution_spl", `Token-2022 execution failed: ${message}`);
|
||||
} finally {
|
||||
@@ -750,7 +845,12 @@ async function loadTokenJournal(): Promise<void> {
|
||||
});
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
element<HTMLTextAreaElement>("#tokenJournalDetailOutput").value = JSON.stringify({ error: message }, null, 2);
|
||||
element<HTMLTextAreaElement>("#tokenJournalDetailOutput").value = JSON.stringify({
|
||||
title: "Journal métier SPL Token",
|
||||
status: "error",
|
||||
message,
|
||||
error: message,
|
||||
}, null, 2);
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_execution_spl", `Token journal loading failed: ${message}`);
|
||||
} finally {
|
||||
button.disabled = false;
|
||||
@@ -788,6 +888,27 @@ async function cancelExecution(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function prepareSelectedProfile(): Promise<void> {
|
||||
const profile = selectedProfile();
|
||||
profileStoreReady = false;
|
||||
setRunning(running);
|
||||
if (!profile) {
|
||||
return;
|
||||
}
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "info", stage: "store_prepare", message: `Vérification PostgreSQL du profil ${profile.name}.` });
|
||||
try {
|
||||
const readiness = await invoke<DemoExecutionDevnetStoreReadinessPayload>("demo_execution_devnet_prepare_profile", { profileName: profile.name });
|
||||
profileStoreReady = true;
|
||||
appendLog({ timestamp: new Date().toISOString(), level: "info", stage: "store_ready", message: `PostgreSQL prêt: ${readiness.existingTablesAfter}/${readiness.expectedTables} tables, créées=${readiness.createdTables}, autoInit=${readiness.autoInitializeSchema}.` });
|
||||
} catch (caughtError) {
|
||||
const message = caughtError instanceof Error ? caughtError.message : String(caughtError);
|
||||
frontendError("kb-app-demo-desktop.frontend.demo_execution_spl", `Devnet store preparation failed: ${message}`);
|
||||
} finally {
|
||||
setRunning(running);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadOptions(): Promise<void> {
|
||||
const options = await invoke<DemoExecutionSolanaCoreOptionsPayload>("demo_execution_solana_core_options");
|
||||
profileOptions = options.profiles;
|
||||
@@ -803,6 +924,7 @@ async function loadOptions(): Promise<void> {
|
||||
element<HTMLInputElement>("#executionLamportsInput").value = String(options.defaultTransferLamports);
|
||||
updateProfileHelp();
|
||||
setRunning(options.running);
|
||||
await prepareSelectedProfile();
|
||||
if (profileOptions.length === 0) {
|
||||
element<HTMLButtonElement>("#simulateExecutionButton").disabled = true;
|
||||
element<HTMLButtonElement>("#submitExecutionButton").disabled = true;
|
||||
@@ -824,7 +946,10 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
installFrontendConsoleBridge("kb-app-demo-desktop.frontend.demo_execution_spl");
|
||||
frontendDebug("kb-app-demo-desktop.frontend.demo_execution_spl", "execution demo window loaded");
|
||||
document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(item => new bootstrap.Tooltip(item));
|
||||
element<HTMLSelectElement>("#executionProfileSelect").addEventListener("change", updateProfileHelp);
|
||||
element<HTMLSelectElement>("#executionProfileSelect").addEventListener("change", () => {
|
||||
updateProfileHelp();
|
||||
void prepareSelectedProfile();
|
||||
});
|
||||
element<HTMLButtonElement>("#generateRecipientButton").addEventListener("click", () => {
|
||||
void generateRecipient();
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/src/demo_decode_replay.rs
|
||||
// version: 32
|
||||
// version: 33
|
||||
|
||||
//! Tauri commands and UI payloads for contextual instruction decode replay.
|
||||
|
||||
@@ -600,7 +600,7 @@ pub(crate) fn coverage_payload(
|
||||
pub(crate) fn annotation_payload(
|
||||
row: kb_store::MaterializedEventQueryRow,
|
||||
) -> std::result::Result<crate::DemoTransactionAnnotationRow, std::string::String> {
|
||||
if row.processor_name != "transaction_annotations"
|
||||
if row.processor_name != "materializer.transaction.annotations"
|
||||
|| row.materialized_family != "transaction_annotation"
|
||||
{
|
||||
return std::result::Result::Err(
|
||||
@@ -720,9 +720,9 @@ mod tests {
|
||||
program_id: kb_lib::MdProgramId(
|
||||
kb_program_ids::ASSOCIATED_TOKEN_PROGRAM_ID.to_string(),
|
||||
),
|
||||
protocol_code: kb_lib::MdProtocolCode("spl_associated_token_account".to_string()),
|
||||
surface_code: kb_lib::MdSurfaceCode("spl_associated_token_account".to_string()),
|
||||
event_code: kb_lib::MdEventCode(format!("spl_associated_token_account.{entry}")),
|
||||
protocol_code: kb_lib::MdProtocolCode("spl.associated_token_account".to_string()),
|
||||
surface_code: kb_lib::MdSurfaceCode("spl.associated_token_account".to_string()),
|
||||
event_code: kb_lib::MdEventCode(format!("spl.associated_token_account.{entry}")),
|
||||
event_name: kb_lib::MdEventName(entry.to_string()),
|
||||
event_family: kb_lib::MdEventFamily::Lifecycle,
|
||||
source_kind: kb_lib::MdEventSourceKind::Instruction,
|
||||
@@ -750,13 +750,13 @@ mod tests {
|
||||
.collect::<std::vec::Vec<_>>();
|
||||
names.sort();
|
||||
let mut expected_names = std::vec![
|
||||
"metadata_metaplex_token_metadata".to_string(),
|
||||
"solana_native_classifier".to_string(),
|
||||
"spl_associated_token_account".to_string(),
|
||||
"spl_elgamal_registry".to_string(),
|
||||
"spl_memo".to_string(),
|
||||
"spl_token".to_string(),
|
||||
"spl_token_2022".to_string(),
|
||||
"metadata.metaplex_token_metadata".to_string(),
|
||||
"solana.core".to_string(),
|
||||
"spl.associated_token_account".to_string(),
|
||||
"spl.elgamal_registry".to_string(),
|
||||
"spl.memo".to_string(),
|
||||
"spl.token".to_string(),
|
||||
"spl.token_2022".to_string(),
|
||||
];
|
||||
expected_names.sort();
|
||||
assert_eq!(names, expected_names);
|
||||
@@ -773,14 +773,14 @@ mod tests {
|
||||
assert_eq!(
|
||||
names,
|
||||
std::vec![
|
||||
"solana_native_admin".to_string(),
|
||||
"solana_native_compliance_audit".to_string(),
|
||||
"fees".to_string(),
|
||||
"solana_native_lifecycle".to_string(),
|
||||
"solana_native_staking".to_string(),
|
||||
"spl_token_accounts".to_string(),
|
||||
"spl_token_risk".to_string(),
|
||||
"transaction_annotations".to_string(),
|
||||
"materializer.admin".to_string(),
|
||||
"materializer.compliance.audit".to_string(),
|
||||
"materializer.fees".to_string(),
|
||||
"materializer.lifecycle".to_string(),
|
||||
"materializer.staking".to_string(),
|
||||
"materializer.token.accounts".to_string(),
|
||||
"materializer.risk".to_string(),
|
||||
"materializer.transaction.annotations".to_string(),
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -788,10 +788,13 @@ mod tests {
|
||||
#[test]
|
||||
fn ata_materializer_ownership_is_exact_in_the_runtime_registry() {
|
||||
for (entry, expected) in [
|
||||
("create", std::vec!["spl_token_accounts".to_string()]),
|
||||
("create", std::vec!["materializer.token.accounts".to_string()]),
|
||||
(
|
||||
"recover_nested",
|
||||
std::vec!["spl_token_accounts".to_string(), "spl_token_risk".to_string(),],
|
||||
std::vec![
|
||||
"materializer.token.accounts".to_string(),
|
||||
"materializer.risk".to_string(),
|
||||
],
|
||||
),
|
||||
] {
|
||||
let observation = ata_observation(entry);
|
||||
@@ -821,7 +824,7 @@ mod tests {
|
||||
program_id: std::option::Option::None,
|
||||
instruction_state: "actionable".to_string(),
|
||||
instruction_paths_text: std::option::Option::None,
|
||||
decoder_names: std::vec!["solana_native_classifier".to_string()],
|
||||
decoder_names: std::vec!["solana.core".to_string()],
|
||||
limit: 10,
|
||||
max_concurrent_inputs: 2,
|
||||
all_compatible: false,
|
||||
@@ -918,12 +921,12 @@ mod tests {
|
||||
#[test]
|
||||
fn committed_annotation_row_is_mapped_to_ui_safe_contract() {
|
||||
let row = kb_store::MaterializedEventQueryRow {
|
||||
processor_name: "transaction_annotations".to_string(),
|
||||
processor_name: "materializer.transaction.annotations".to_string(),
|
||||
processor_version: "0.4.3".to_string(),
|
||||
input_key: "input".to_string(),
|
||||
output_key: "output".to_string(),
|
||||
source_event_key: "memo:0".to_string(),
|
||||
source_decoder_name: "spl_memo".to_string(),
|
||||
source_decoder_name: "spl.memo".to_string(),
|
||||
source_decoder_version: "0.4.3".to_string(),
|
||||
signature: "signature".to_string(),
|
||||
slot: u64::MAX,
|
||||
@@ -954,12 +957,12 @@ mod tests {
|
||||
#[test]
|
||||
fn malformed_annotation_payload_fails_closed() {
|
||||
let row = kb_store::MaterializedEventQueryRow {
|
||||
processor_name: "transaction_annotations".to_string(),
|
||||
processor_name: "materializer.transaction.annotations".to_string(),
|
||||
processor_version: "0.4.3".to_string(),
|
||||
input_key: "input".to_string(),
|
||||
output_key: "output".to_string(),
|
||||
source_event_key: "memo:0".to_string(),
|
||||
source_decoder_name: "spl_memo".to_string(),
|
||||
source_decoder_name: "spl.memo".to_string(),
|
||||
source_decoder_version: "0.4.3".to_string(),
|
||||
signature: "signature".to_string(),
|
||||
slot: 1,
|
||||
|
||||
50
kb-app-demo-desktop/src/demo_devnet_common.rs
Normal file
50
kb-app-demo-desktop/src/demo_devnet_common.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
// file: kb-app-demo-desktop/src/demo_devnet_common.rs
|
||||
// version: 2
|
||||
|
||||
//! Shared Devnet demo UI contracts.
|
||||
|
||||
use ts_rs::TS; // rust-rules: derive-import
|
||||
|
||||
/// Readiness report for one Devnet profile PostgreSQL store.
|
||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_app_demo_desktop/demo_execution_solana_core/DemoExecutionDevnetStoreReadinessPayload.ts"
|
||||
)]
|
||||
pub(crate) struct DemoExecutionDevnetStoreReadinessPayload {
|
||||
/// Selected Devnet profile.
|
||||
pub(crate) profile_name: std::string::String,
|
||||
/// Whether schema creation was allowed by configuration.
|
||||
pub(crate) auto_initialize_schema: bool,
|
||||
/// Number of known tables already present before preparation.
|
||||
pub(crate) existing_tables_before: u32,
|
||||
/// Number of known tables created during preparation.
|
||||
pub(crate) created_tables: u32,
|
||||
/// Number of known tables present after preparation.
|
||||
pub(crate) existing_tables_after: u32,
|
||||
/// Total number of known tables expected by the current store.
|
||||
pub(crate) expected_tables: u32,
|
||||
}
|
||||
|
||||
/// Converts one collection length to the bounded UI counter type.
|
||||
fn bounded_u32(value: usize) -> u32 {
|
||||
return match u32::try_from(value) {
|
||||
std::result::Result::Ok(converted) => converted,
|
||||
std::result::Result::Err(_) => u32::MAX,
|
||||
};
|
||||
}
|
||||
|
||||
/// Converts the reusable scenario readiness report to the desktop TS-RS payload.
|
||||
pub(crate) fn devnet_store_readiness_payload(
|
||||
readiness: kb_pipeline_demo_scenarios::DevnetProfileStoreReadiness,
|
||||
) -> DemoExecutionDevnetStoreReadinessPayload {
|
||||
return DemoExecutionDevnetStoreReadinessPayload {
|
||||
profile_name: readiness.profile_name,
|
||||
auto_initialize_schema: readiness.auto_initialize_schema,
|
||||
existing_tables_before: bounded_u32(readiness.existing_tables_before),
|
||||
created_tables: bounded_u32(readiness.created_tables),
|
||||
existing_tables_after: bounded_u32(readiness.existing_tables_after),
|
||||
expected_tables: bounded_u32(readiness.expected_tables),
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/src/demo_execution_solana_core.rs
|
||||
// version: 6
|
||||
// version: 8
|
||||
|
||||
//! Tauri adapter for bounded Solana Core execution on Devnet.
|
||||
|
||||
@@ -395,18 +395,11 @@ pub(crate) fn select_devnet_profile(
|
||||
config: &kb_config::AppConfig,
|
||||
profile_name: &str,
|
||||
) -> std::result::Result<kb_config::ProfileConfig, std::string::String> {
|
||||
for profile in &config.profiles {
|
||||
if profile.name == profile_name
|
||||
&& profile.wallet.cluster == "devnet"
|
||||
&& profile.wallet.temporary_wallet_enabled
|
||||
&& profile.wallet.temporary_wallet_persist
|
||||
{
|
||||
return std::result::Result::Ok(profile.clone());
|
||||
}
|
||||
}
|
||||
return std::result::Result::Err(format!(
|
||||
"Devnet execution profile '{profile_name}' is unavailable"
|
||||
));
|
||||
return kb_pipeline_demo_scenarios::resolve_demo_devnet_profile(
|
||||
config,
|
||||
std::option::Option::Some(profile_name),
|
||||
)
|
||||
.map_err(|error| return error.to_string());
|
||||
}
|
||||
|
||||
pub(crate) fn demo_execution_solana_core_summary_payload(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/src/demo_spl_token.rs
|
||||
// version: 3
|
||||
// version: 4
|
||||
|
||||
//! Thin Tauri adapter for classic SPL Token execution and materialized journals.
|
||||
|
||||
@@ -109,7 +109,7 @@ pub(crate) struct DemoSplTokenJournalRequest {
|
||||
pub(crate) account: std::option::Option<std::string::String>,
|
||||
/// Optional exact materialized family.
|
||||
pub(crate) family: std::option::Option<std::string::String>,
|
||||
/// Optional exact operation code without the `spl_token.` prefix.
|
||||
/// Optional exact operation code without the `spl.token.` prefix.
|
||||
pub(crate) operation: std::option::Option<std::string::String>,
|
||||
/// Maximum number of rows returned after typed filtering.
|
||||
pub(crate) limit: u32,
|
||||
@@ -463,12 +463,12 @@ mod tests {
|
||||
std::option::Option::Some("18446744073709551615")
|
||||
);
|
||||
let row = crate::demo_spl_token_journal_row(kb_store::MaterializedEventQueryRow {
|
||||
processor_name: "spl_token_accounts".to_string(),
|
||||
processor_name: "materializer.token.accounts".to_string(),
|
||||
processor_version: "0.4.4".to_string(),
|
||||
input_key: "input".to_string(),
|
||||
output_key: "output".to_string(),
|
||||
source_event_key: "event".to_string(),
|
||||
source_decoder_name: "spl_token".to_string(),
|
||||
source_decoder_name: "spl.token".to_string(),
|
||||
source_decoder_version: "0.4.4".to_string(),
|
||||
signature: "signature".to_string(),
|
||||
slot: u64::MAX,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/src/demo_spl_token_2022.rs
|
||||
// version: 6
|
||||
// version: 7
|
||||
|
||||
//! Thin Tauri adapter for independent public Token-2022 Devnet validation scenarios.
|
||||
|
||||
@@ -33,8 +33,14 @@ pub(crate) struct DemoSplToken2022FixturePayload {
|
||||
pub(crate) freeze_authority: std::string::String,
|
||||
/// Mint decimals.
|
||||
pub(crate) decimals: u8,
|
||||
/// Default raw amount for the selected scenario.
|
||||
pub(crate) default_amount_raw: std::string::String,
|
||||
/// Raw amount used by `MintToChecked`.
|
||||
pub(crate) mint_amount_raw: std::string::String,
|
||||
/// Raw amount used by `TransferChecked`.
|
||||
pub(crate) transfer_amount_raw: std::string::String,
|
||||
/// Raw amount used by `ApproveChecked`.
|
||||
pub(crate) approve_amount_raw: std::string::String,
|
||||
/// Raw amount used by `BurnChecked`.
|
||||
pub(crate) burn_amount_raw: std::string::String,
|
||||
}
|
||||
|
||||
/// Request for one independent public Token-2022 Devnet scenario.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/src/lib.rs
|
||||
// version: 13
|
||||
// version: 15
|
||||
|
||||
//! Tauri desktop demo application for `khadhroony-bot3`.
|
||||
|
||||
@@ -13,6 +13,7 @@ mod demo_backfill;
|
||||
mod demo_config;
|
||||
mod demo_core_extraction;
|
||||
mod demo_decode_replay;
|
||||
mod demo_devnet_common;
|
||||
mod demo_execution_solana_core;
|
||||
mod demo_execution_spl;
|
||||
mod demo_http;
|
||||
@@ -129,6 +130,10 @@ pub(crate) use self::demo_decode_replay::optional_line_count;
|
||||
pub(crate) use self::demo_decode_replay::register_active_campaign;
|
||||
/// Internal demo decode replay item.
|
||||
pub(crate) use self::demo_decode_replay::text_sample;
|
||||
/// Readiness report for one Devnet profile PostgreSQL store.
|
||||
pub(crate) use self::demo_devnet_common::DemoExecutionDevnetStoreReadinessPayload;
|
||||
/// Converts the reusable scenario readiness report to the desktop TS-RS payload.
|
||||
pub(crate) use self::demo_devnet_common::devnet_store_readiness_payload;
|
||||
/// Request sent by the Memo v4 Devnet execution panel.
|
||||
pub(crate) use self::demo_execution_solana_core::DemoExecutionMemoRequest;
|
||||
/// UI-safe result of one Memo v4 Devnet execution orchestration.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-app-demo-desktop/src/tauri.rs
|
||||
// version: 17
|
||||
// version: 21
|
||||
|
||||
//! Tauri runtime assembly and private command wrappers.
|
||||
|
||||
@@ -67,6 +67,7 @@ pub fn run() -> kb_core::Result<()> {
|
||||
load_demo_sql_replay_entities,
|
||||
export_demo_sql_replay_csv,
|
||||
demo_execution_solana_core_options,
|
||||
demo_execution_devnet_prepare_profile,
|
||||
demo_execution_solana_core_generate_recipient,
|
||||
demo_execution_solana_core_execute,
|
||||
open_demo_execution_solana_core_window,
|
||||
@@ -498,7 +499,7 @@ async fn demo_decode_replay_annotations(
|
||||
request: crate::DemoTransactionAnnotationRequest,
|
||||
) -> std::result::Result<std::vec::Vec<crate::DemoTransactionAnnotationRow>, std::string::String> {
|
||||
let filter_result = kb_store::MaterializedEventFilter::new(
|
||||
std::option::Option::Some("transaction_annotations".to_string()),
|
||||
std::option::Option::Some("materializer.transaction.annotations".to_string()),
|
||||
std::option::Option::Some("transaction_annotation".to_string()),
|
||||
request.signature_contains,
|
||||
request.limit,
|
||||
@@ -1106,6 +1107,26 @@ fn open_demo_execution_solana_core_window(
|
||||
);
|
||||
}
|
||||
|
||||
/// Verifies or initializes the PostgreSQL schema selected by one Devnet profile.
|
||||
#[tauri::command]
|
||||
async fn demo_execution_devnet_prepare_profile(
|
||||
state: tauri::State<'_, crate::AppState>,
|
||||
profile_name: std::string::String,
|
||||
) -> std::result::Result<crate::DemoExecutionDevnetStoreReadinessPayload, std::string::String> {
|
||||
let profile = match crate::select_devnet_profile(state.app_config(), profile_name.as_str()) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let readiness =
|
||||
match kb_pipeline_demo_scenarios::prepare_demo_devnet_profile_store(&profile).await {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(error.to_string());
|
||||
},
|
||||
};
|
||||
return std::result::Result::Ok(crate::devnet_store_readiness_payload(readiness));
|
||||
}
|
||||
|
||||
/// Returns compatible Devnet profiles and conservative defaults.
|
||||
#[tauri::command]
|
||||
fn demo_execution_solana_core_options(
|
||||
@@ -1506,7 +1527,7 @@ async fn demo_spl_token_journal(
|
||||
};
|
||||
let mut output = std::vec::Vec::new();
|
||||
for row in rows {
|
||||
if row.source_decoder_name != "spl_token"
|
||||
if row.source_decoder_name != "spl.token"
|
||||
|| !crate::payload_matches(&row.payload_json, &validated)
|
||||
{
|
||||
continue;
|
||||
@@ -1683,7 +1704,7 @@ async fn demo_spl_ata_journal(
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error.to_string()),
|
||||
};
|
||||
let filter = match kb_store::MaterializedEventFilter::new(
|
||||
std::option::Option::Some("spl_token_accounts".to_string()),
|
||||
std::option::Option::Some("materializer.token.accounts".to_string()),
|
||||
std::option::Option::None,
|
||||
request.signature_contains.clone(),
|
||||
500,
|
||||
@@ -1698,7 +1719,7 @@ async fn demo_spl_ata_journal(
|
||||
};
|
||||
let mut output = std::vec::Vec::new();
|
||||
for row in rows {
|
||||
if row.source_decoder_name != "spl_associated_token_account"
|
||||
if row.source_decoder_name != "spl.associated_token_account"
|
||||
|| !crate::journal_matches(&row.payload_json, &request)
|
||||
{
|
||||
continue;
|
||||
@@ -1886,9 +1907,21 @@ fn demo_spl_token_2022_fixture(
|
||||
authority,
|
||||
freeze_authority,
|
||||
decimals,
|
||||
default_amount_raw: values
|
||||
.get("TOKEN_2022_TRANSFER_AMOUNT_RAW")
|
||||
.cloned()
|
||||
.unwrap_or_else(|| return "1".to_string()),
|
||||
mint_amount_raw: match required("TOKEN_2022_MINT_AMOUNT_RAW") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
},
|
||||
transfer_amount_raw: match required("TOKEN_2022_TRANSFER_AMOUNT_RAW") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
},
|
||||
approve_amount_raw: match required("TOKEN_2022_APPROVE_AMOUNT_RAW") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
},
|
||||
burn_amount_raw: match required("TOKEN_2022_BURN_AMOUNT_RAW") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user