v0.1.0-pre.076

This commit is contained in:
2026-08-01 16:23:15 +02:00
parent f4331cf48a
commit d7284ab71e
27 changed files with 2273 additions and 2020 deletions

View File

@@ -1,5 +1,5 @@
// file: kb-app-demo-desktop/src/demo_spl_token.rs
// version: 4
// version: 8
//! Thin Tauri adapter for classic SPL Token execution and materialized journals.
@@ -153,7 +153,152 @@ pub(crate) struct DemoSplTokenJournalRow {
pub(crate) updated_at: std::string::String,
}
pub(crate) fn demo_spl_token_summary_payload(
/// Executes one checked SPL Token simulation or explicitly authorized Devnet submission.
pub(crate) async fn demo_execution_spl_token_execute(
app_handle: tauri::AppHandle,
state: tauri::State<'_, crate::AppState>,
request: crate::DemoExecutionSplTokenRequest,
) -> std::result::Result<crate::DemoExecutionSplTokenSummaryPayload, std::string::String> {
let acquire_result = state.demo_execution_solana_core_running().compare_exchange(
false,
true,
std::sync::atomic::Ordering::AcqRel,
std::sync::atomic::Ordering::Acquire,
);
if acquire_result.is_err() {
return std::result::Result::Err("a Devnet execution is already running".to_string());
}
let _run_guard = crate::DemoExecutionSolanaCoreRunGuard {
running: state.demo_execution_solana_core_running(),
};
state
.demo_execution_solana_core_cancel_requested()
.store(false, std::sync::atomic::Ordering::Release);
let profile =
match crate::select_devnet_profile(state.app_config(), request.profile_name.as_str()) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let http_pool = match kb_onchain_transport::HttpEndpointPool::from_profile(&profile) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error.to_string()),
};
let store = match crate::connect_postgres_store(&profile).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error.to_string()),
};
if let std::result::Result::Err(error) = store.initialize_store_schema().await {
return std::result::Result::Err(error.to_string());
}
let amount_raw = request.amount_raw.trim().to_string();
let operation = kb_lib::ExSplClassicTokenOperation::Instruction {
value: kb_lib::ExSplClassicTokenSingleOperation::TransferChecked {
source: kb_lib::MdPubkey(request.source.trim().to_string()),
mint: kb_lib::MdPubkey(request.mint.trim().to_string()),
destination: kb_lib::MdPubkey(request.destination.trim().to_string()),
authority: kb_lib::ExSplClassicTokenAuthority {
authority: kb_lib::MdPubkey(request.authority.trim().to_string()),
multisig_signers: std::vec::Vec::new(),
},
amount: kb_lib::ExSplClassicTokenAmount(amount_raw.clone()),
decimals: request.decimals,
},
};
let mut pipeline_request = kb_pipeline_demo_scenarios::DevnetSplTokenExecutionRequest::new(
format!("demo-spl-token-execution-{}", chrono::Utc::now().timestamp_micros()),
operation,
);
pipeline_request.submit = request.submit;
pipeline_request.operator_confirmed = request.operator_confirmed;
pipeline_request.post_validation_max_retries = 20;
pipeline_request.force_post_validation_replay = request.force_post_validation_replay;
let decoders: std::vec::Vec<std::sync::Arc<dyn kb_lib::DcApiInstructionDecoder>> =
std::vec![std::sync::Arc::new(kb_lib::DcSplTokenDecoder)];
let materializers: std::vec::Vec<std::sync::Arc<dyn kb_lib::MtApiEventMaterializer>> = std::vec![
std::sync::Arc::new(kb_lib::MtTokenAccountsMaterializer),
std::sync::Arc::new(kb_lib::MtAdminMaterializer),
std::sync::Arc::new(kb_lib::MtRiskMaterializer),
];
let observer = crate::DemoExecutionSolanaCoreObserver {
app_handle,
cancel_requested: state.demo_execution_solana_core_cancel_requested(),
};
let workspace_root = crate::workspace_root_dir();
let summary = match kb_pipeline_demo_scenarios::execute_devnet_spl_token(
&http_pool,
&store,
&profile,
workspace_root.as_path(),
&pipeline_request,
decoders.as_slice(),
materializers.as_slice(),
&observer,
)
.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(summary_payload(summary, amount_raw, request.decimals));
}
/// Loads a bounded, typed journal of committed classic SPL Token projections.
pub(crate) async fn demo_spl_token_journal(
state: tauri::State<'_, crate::AppState>,
request: crate::DemoSplTokenJournalRequest,
) -> std::result::Result<std::vec::Vec<crate::DemoSplTokenJournalRow>, std::string::String> {
let validated = match validate_journal_request(request) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let profile =
match crate::select_devnet_profile(state.app_config(), validated.profile_name.as_str()) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let store = match crate::connect_postgres_store(&profile).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error.to_string()),
};
if let std::result::Result::Err(error) = store.initialize_store_schema().await {
return std::result::Result::Err(error.to_string());
}
let needs_payload_filter =
validated.mint.is_some() || validated.account.is_some() || validated.operation.is_some();
let query_limit = if needs_payload_filter {
kb_store::MAX_MATERIALIZED_EVENT_QUERY_ROWS
} else {
validated.limit
};
let filter = match kb_store::MaterializedEventFilter::new(
std::option::Option::None,
validated.family.clone(),
validated.signature_contains.clone(),
query_limit,
) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error.to_string()),
};
let rows = match kb_store::DecodePipelineStore::list_materialized_events(&store, &filter).await
{
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error.to_string()),
};
let mut output = std::vec::Vec::new();
for row in rows {
if row.source_decoder_name != "spl.token" || !payload_matches(&row.payload_json, &validated)
{
continue;
}
output.push(journal_row(row));
if output.len() >= validated.limit as usize {
break;
}
}
return std::result::Result::Ok(output);
}
fn summary_payload(
summary: kb_pipeline_demo_scenarios::DevnetSplTokenExecutionSummary,
amount_raw: std::string::String,
decimals: u8,
@@ -267,7 +412,7 @@ fn replay_diagnostics(summary: &kb_pipeline::DecodeReplaySummary) -> serde_json:
});
}
pub(crate) fn validate_journal_request(
fn validate_journal_request(
request: crate::DemoSplTokenJournalRequest,
) -> std::result::Result<crate::DemoSplTokenJournalRequest, std::string::String> {
if request.limit == 0 || request.limit > kb_store::MAX_MATERIALIZED_EVENT_QUERY_ROWS {
@@ -331,7 +476,7 @@ fn bounded_optional(
return std::result::Result::Ok(trimmed);
}
pub(crate) fn payload_matches(
fn payload_matches(
payload: &serde_json::Value,
request: &crate::DemoSplTokenJournalRequest,
) -> bool {
@@ -354,9 +499,7 @@ pub(crate) fn payload_matches(
return true;
}
pub(crate) fn demo_spl_token_journal_row(
row: kb_store::MaterializedEventQueryRow,
) -> DemoSplTokenJournalRow {
fn journal_row(row: kb_store::MaterializedEventQueryRow) -> DemoSplTokenJournalRow {
let operation = row
.payload_json
.get("operation")
@@ -457,12 +600,12 @@ mod tests {
{"role": "mint", "accountKey": "mint111"}
]
});
assert!(crate::payload_matches(&payload, &request));
assert!(super::payload_matches(&payload, &request));
assert_eq!(
payload.get("amountRaw").and_then(serde_json::Value::as_str),
std::option::Option::Some("18446744073709551615")
);
let row = crate::demo_spl_token_journal_row(kb_store::MaterializedEventQueryRow {
let row = super::journal_row(kb_store::MaterializedEventQueryRow {
processor_name: "materializer.token.accounts".to_string(),
processor_version: "0.4.4".to_string(),
input_key: "input".to_string(),
@@ -492,6 +635,6 @@ mod tests {
operation: std::option::Option::None,
limit: 501,
};
assert!(crate::validate_journal_request(request).is_err());
assert!(super::validate_journal_request(request).is_err());
}
}