v0.5.2-pre.006-fix-010

This commit is contained in:
2026-08-11 12:03:35 +02:00
parent 1ee1d0297d
commit 56572cec40
67 changed files with 2484 additions and 539 deletions

View File

@@ -1,8 +1,20 @@
<!-- file: ks-pipeline-demo-scenarios/CHANGELOG.md -->
<!-- version: 79 -->
<!-- version: 81 -->
# CHANGELOG — ks-pipeline-demo-scenarios
## `0.5.2-pre.006-delta-fix-006`
- corrige le wrapper pNFT legacy : il reprend son paramètre `workspace_root` historique et construit le wallet temporaire uniquement dans ce wrapper, tandis que la variante `_with_wallet` conserve le signer explicite ;
- retire l'initialisation du champ inexistant `wallet` dans `PreparedToken2022Execution`, le signer restant fourni explicitement par l'appelant lors de la signature après simulation.
## `0.5.2-pre.006-delta-fix-005`
- introduit `DevnetExecutionWallet` comme capacité de signature commune aux wallets temporaires et aux `.kswallet` authentifiés, sans accès aux bytes privés ;
- résout explicitement `wallet_alias` vers un `.kswallet` déverrouillé et interdit toujours tout fallback silencieux vers le JSON temporaire ;
- sépare les chemins persistants et temporaires dans les scénarios/fixtures, puis branche System, Memo, ATA, SPL Token, Token-2022, Solana Program Metadata et Token-2022 Metadata sur un signer explicitement résolu ;
- propage le même signer persistant à toutes les campagnes Metaplex du desktop, y compris les parcours multi-signers ; les mints, delegates et destinations réellement jetables restent des keypairs temporaires distinctes.
## `0.5.2-pre.006`
- ajoute l'inspection et l'unlock explicites du wallet natif sélectionné par `profile.wallet.wallet_alias`, avec `WalletPassword` fourni uniquement au runtime ;

View File

@@ -1,11 +1,11 @@
<!-- file: ks-pipeline-demo-scenarios/TODO.md -->
<!-- version: 44 -->
<!-- version: 45 -->
# TODO — ks-pipeline-demo-scenarios
## Évolutions générales
- [ ] `0.5.2`refactorer les runners Devnet qui appellent encore directement `load_profile_temporary_wallet()` afin qu'ils puissent recevoir une capacité signer issue d'un `.kswallet` explicitement déverrouillé, sans fallback silencieux.
- [ ] `0.5.4`inventorier/classifier les keypairs de fixtures historiques sous `wallets/temporary/**` et préparer leur migration sélective lorsque leur rôle doit devenir persistant.
- [ ] `0.5.4` — centraliser les dispatchs, compositions decoder/materializer et critères de complétion encore réutilisables depuis le desktop.
- [ ] `0.5.4` — produire la matrice active decoder/materializer/executor/scénario/preuve sans transformer les surfaces réservées en dettes implicites.
- [ ] Ajouter au CLI uniquement les préparations de fixtures explicitement justifiées.

View File

@@ -1,5 +1,5 @@
<!-- file: ks-pipeline-demo-scenarios/USAGE.md -->
<!-- version: 32 -->
<!-- version: 33 -->
# Utilisation de ks-pipeline-demo-scenarios
@@ -312,7 +312,7 @@ cargo test -p ks-pipeline-demo-scenarios optional_devnet_current_operation_from_
Variables optionnelles :
- `KS_DEVNET_WALLET_DIR` pour sélectionner le répertoire du wallet persistant ;
- `KS_DEVNET_WALLET_DIR` pour surcharger le répertoire legacy de fixtures/wallets temporaires du test opt-in ;
- `KS_SECRET_POSTGRES_TEST_URL` est obligatoire pour le test opt-in afin de permettre lhydratation canonique, lextraction Core, le replay et la vérification didempotence après une soumission ;
- `KS_DEVNET_METAPLEX_PREFLIGHT_READS_JSON` pour fournir les lectures stateful avant simulation ;
- `KS_DEVNET_METAPLEX_POSTCONDITION_READS_JSON` pour fournir les lectures après confirmation ;

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/lib.rs
// version: 30
// version: 31
#![forbid(unsafe_code)]
#![deny(unreachable_pub)]
@@ -12,6 +12,7 @@ mod environment;
mod metadata;
mod solana;
mod spl;
mod wallet;
/// Readiness report for one Devnet profile PostgreSQL store.
pub use self::environment::DevnetProfileStoreReadiness;
@@ -29,6 +30,8 @@ pub use self::metadata::metaplex_token_metadata::collection_verify_campaign::Dev
pub use self::metadata::metaplex_token_metadata::collection_verify_campaign::DevnetMetaplexCollectionVerifyState;
/// Executes one fresh collection parent/member verification campaign on Devnet.
pub use self::metadata::metaplex_token_metadata::collection_verify_campaign::execute_devnet_metaplex_collection_verify_campaign;
/// Executes one collection verification campaign with an explicit operator wallet.
pub use self::metadata::metaplex_token_metadata::collection_verify_campaign::execute_devnet_metaplex_collection_verify_campaign_with_wallet;
/// Returns the exact current operations qualified by the collection verification campaign.
pub use self::metadata::metaplex_token_metadata::collection_verify_campaign::metaplex_collection_verify_campaign_operation_names;
/// Complete evidence produced by one family-specific Metaplex `Create -> Mint` campaign.
@@ -37,6 +40,8 @@ pub use self::metadata::metaplex_token_metadata::create_mint_campaign::DevnetMet
pub use self::metadata::metaplex_token_metadata::create_mint_campaign::DevnetMetaplexCreateMintTokenState;
/// Executes one fresh family-specific Metaplex `Create -> Mint` campaign on Devnet.
pub use self::metadata::metaplex_token_metadata::create_mint_campaign::execute_devnet_metaplex_create_mint_campaign;
/// Executes one family-specific Metaplex `Create -> Mint` campaign with an explicit operator wallet.
pub use self::metadata::metaplex_token_metadata::create_mint_campaign::execute_devnet_metaplex_create_mint_campaign_with_wallet;
/// Returns the exact ordered operations covered by the `Create -> Mint` campaign.
pub use self::metadata::metaplex_token_metadata::create_mint_campaign::metaplex_create_mint_campaign_operation_names;
/// Complete request for one real Devnet Metaplex Token Metadata execution.
@@ -51,18 +56,26 @@ pub use self::metadata::metaplex_token_metadata::devnet_execution::devnet_metapl
pub use self::metadata::metaplex_token_metadata::devnet_execution::execute_devnet_metaplex_token_metadata;
/// Executes one real Devnet Metaplex submission with explicitly authorized extra signers.
pub use self::metadata::metaplex_token_metadata::devnet_execution::execute_devnet_metaplex_token_metadata_with_signers;
/// Executes one real Devnet Metaplex operation with an explicitly resolved wallet.
pub use self::metadata::metaplex_token_metadata::devnet_execution::execute_devnet_metaplex_token_metadata_with_wallet;
/// Executes one real Devnet Metaplex submission with an explicit wallet and extra signers.
pub use self::metadata::metaplex_token_metadata::devnet_execution::execute_devnet_metaplex_token_metadata_with_wallet_and_signers;
/// Returns a formatted JSON template for one named current operation.
pub use self::metadata::metaplex_token_metadata::devnet_execution::metaplex_token_metadata_current_operation_json_template;
/// Returns the current operation names accepted by automatic Devnet campaigns.
pub use self::metadata::metaplex_token_metadata::devnet_execution::metaplex_token_metadata_current_operation_names;
/// Simulates one current Metaplex operation against a real Devnet endpoint.
pub use self::metadata::metaplex_token_metadata::devnet_execution::simulate_devnet_metaplex_token_metadata;
/// Simulates one current Metaplex operation with an explicitly resolved wallet.
pub use self::metadata::metaplex_token_metadata::devnet_execution::simulate_devnet_metaplex_token_metadata_with_wallet;
/// Exact SPL state transitions exercised around the Token Owned Escrow operations.
pub use self::metadata::metaplex_token_metadata::escrow_campaign::DevnetMetaplexEscrowCampaignState;
/// Complete evidence retained by one Token Owned Escrow Devnet campaign.
pub use self::metadata::metaplex_token_metadata::escrow_campaign::DevnetMetaplexEscrowCampaignSummary;
/// Executes a fresh Token Owned Escrow lifecycle on Devnet.
pub use self::metadata::metaplex_token_metadata::escrow_campaign::execute_devnet_metaplex_escrow_campaign;
/// Executes a Token Owned Escrow lifecycle with an explicit operator wallet.
pub use self::metadata::metaplex_token_metadata::escrow_campaign::execute_devnet_metaplex_escrow_campaign_with_wallet;
/// Returns the exact ordered Metaplex operations qualified by the escrow campaign.
pub use self::metadata::metaplex_token_metadata::escrow_campaign::metaplex_escrow_campaign_operation_names;
/// Options for one Metaplex Create fixture preparation.
@@ -77,6 +90,8 @@ pub(crate) use self::metadata::metaplex_token_metadata::fixture::classic_fixture
pub(crate) use self::metadata::metaplex_token_metadata::fixture::classic_fixture_token_amount;
/// Creates or reuses a classic SPL mint and derives its Metaplex PDAs.
pub use self::metadata::metaplex_token_metadata::fixture::prepare_metaplex_create_fixture;
/// Creates a classic SPL mint fixture using an explicitly resolved operator wallet.
pub use self::metadata::metaplex_token_metadata::fixture::prepare_metaplex_create_fixture_with_wallet;
/// Reads one classic SPL mint account at or after a minimum context slot.
pub(crate) use self::metadata::metaplex_token_metadata::fixture::read_mint_account_at_or_after;
/// Reads one classic SPL token account at or after a minimum context slot.
@@ -89,6 +104,8 @@ pub(crate) use self::metadata::metaplex_token_metadata::fixture::validate_classi
pub use self::metadata::metaplex_token_metadata::maintenance_campaign::DevnetMetaplexMaintenanceCampaignSummary;
/// Executes the final bounded current maintenance campaign on Devnet.
pub use self::metadata::metaplex_token_metadata::maintenance_campaign::execute_devnet_metaplex_maintenance_campaign;
/// Executes the bounded maintenance campaign with an explicit operator wallet.
pub use self::metadata::metaplex_token_metadata::maintenance_campaign::execute_devnet_metaplex_maintenance_campaign_with_wallet;
/// Returns the exact ordered operations exercised by the maintenance campaign.
pub use self::metadata::metaplex_token_metadata::maintenance_campaign::metaplex_maintenance_campaign_operation_names;
/// Complete evidence produced by one pNFT lifecycle campaign.
@@ -97,6 +114,8 @@ pub use self::metadata::metaplex_token_metadata::pnft_lifecycle_campaign::Devnet
pub use self::metadata::metaplex_token_metadata::pnft_lifecycle_campaign::DevnetMetaplexPnftLifecycleState;
/// Executes one fresh pNFT delegate/lock/unlock/revoke/transfer campaign on Devnet.
pub use self::metadata::metaplex_token_metadata::pnft_lifecycle_campaign::execute_devnet_metaplex_pnft_lifecycle_campaign;
/// Executes one pNFT lifecycle campaign with an explicit operator wallet.
pub use self::metadata::metaplex_token_metadata::pnft_lifecycle_campaign::execute_devnet_metaplex_pnft_lifecycle_campaign_with_wallet;
/// Returns the exact ordered current operations exercised by the pNFT lifecycle campaign.
pub use self::metadata::metaplex_token_metadata::pnft_lifecycle_campaign::metaplex_pnft_lifecycle_campaign_operation_names;
/// Complete evidence produced by one printable master NFT `Print -> Burn` campaign.
@@ -105,6 +124,8 @@ pub use self::metadata::metaplex_token_metadata::print_burn_campaign::DevnetMeta
pub use self::metadata::metaplex_token_metadata::print_burn_campaign::DevnetMetaplexPrintBurnState;
/// Executes one printable master NFT `Print -> Burn` campaign on Devnet.
pub use self::metadata::metaplex_token_metadata::print_burn_campaign::execute_devnet_metaplex_print_burn_campaign;
/// Executes one printable master NFT campaign with an explicit operator wallet.
pub use self::metadata::metaplex_token_metadata::print_burn_campaign::execute_devnet_metaplex_print_burn_campaign_with_wallet;
/// Returns the exact ordered current operations qualified by the print/burn campaign.
pub use self::metadata::metaplex_token_metadata::print_burn_campaign::metaplex_print_burn_campaign_operation_names;
/// Stable asset family covered by one Metaplex scenario.
@@ -127,6 +148,8 @@ pub use self::metadata::metaplex_token_metadata::use_campaign::DevnetMetaplexUse
pub use self::metadata::metaplex_token_metadata::use_campaign::DevnetMetaplexUseProbeSummary;
/// Executes one bounded current `Use` availability probe on Devnet.
pub use self::metadata::metaplex_token_metadata::use_campaign::execute_devnet_metaplex_use_probe;
/// Executes one bounded current `Use` probe with an explicit operator wallet.
pub use self::metadata::metaplex_token_metadata::use_campaign::execute_devnet_metaplex_use_probe_with_wallet;
/// Returns the exact setup and target operations exercised by the `Use` probe.
pub use self::metadata::metaplex_token_metadata::use_campaign::metaplex_use_probe_operation_names;
/// Maximum evidence entries accepted by one Metaplex validation scenario.
@@ -173,14 +196,20 @@ pub use self::metadata::solana_program::campaign::DevnetSolanaProgramMetadataCam
pub use self::metadata::solana_program::campaign::DevnetSolanaProgramMetadataCampaignSummary;
/// Prepares fresh accounts and executes the nine stable operations on Devnet.
pub use self::metadata::solana_program::campaign::execute_devnet_solana_program_metadata_campaign;
/// Executes the complete Solana Program Metadata campaign with an explicitly resolved wallet.
pub use self::metadata::solana_program::campaign::execute_devnet_solana_program_metadata_campaign_with_wallet;
/// Complete request for one Solana Program Metadata Devnet execution.
pub use self::metadata::solana_program::devnet_execution::DevnetSolanaProgramMetadataExecutionRequest;
/// Complete evidence produced by one Solana Program Metadata Devnet execution.
pub use self::metadata::solana_program::devnet_execution::DevnetSolanaProgramMetadataExecutionSummary;
/// Executes one Solana Program Metadata simulation or authorized submission.
pub use self::metadata::solana_program::devnet_execution::execute_devnet_solana_program_metadata;
/// Executes one Solana Program Metadata operation with an explicitly resolved wallet.
pub use self::metadata::solana_program::devnet_execution::execute_devnet_solana_program_metadata_with_wallet;
/// Simulates one stable Solana Program Metadata operation against Devnet.
pub use self::metadata::solana_program::devnet_execution::simulate_devnet_solana_program_metadata;
/// Simulates one Solana Program Metadata operation with an explicitly resolved wallet.
pub use self::metadata::solana_program::devnet_execution::simulate_devnet_solana_program_metadata_with_wallet;
/// Bytes reserved for the public Buffer journey before `Trim`.
pub use self::metadata::solana_program::fixture::SOLANA_PROGRAM_METADATA_FIXTURE_BUFFER_DATA_BYTES;
/// Options used to prepare one complete Solana Program Metadata fixture.
@@ -191,6 +220,8 @@ pub use self::metadata::solana_program::fixture::SolanaProgramMetadataFixturePre
pub use self::metadata::solana_program::fixture::SolanaProgramMetadataPreparedStep;
/// Creates two unique pre-funded PDAs and the nine typed journey steps.
pub use self::metadata::solana_program::fixture::prepare_solana_program_metadata_fixture;
/// Creates the Solana Program Metadata fixture with an explicitly resolved wallet.
pub use self::metadata::solana_program::fixture::prepare_solana_program_metadata_fixture_with_wallet;
/// Stable lifecycle state consumed or produced by one scenario step.
pub use self::metadata::solana_program::scenarios::SolanaProgramMetadataFixtureState;
/// One ordered multi-step Solana Program Metadata journey.
@@ -231,6 +262,8 @@ pub(crate) use self::solana::emit;
pub(crate) use self::solana::ensure_not_cancelled;
/// Executes one bounded System Program transfer on Devnet.
pub use self::solana::execute_devnet_system_transfer;
/// Executes one bounded System transfer with an explicitly resolved wallet capability.
pub use self::solana::execute_devnet_system_transfer_with_wallet;
/// Inspects the persistent native wallet alias selected by one execution profile.
pub use self::solana::inspect_selected_profile_wallet;
/// Loads the managed temporary wallet used by legacy Devnet scenarios.
@@ -247,6 +280,8 @@ pub use self::spl::associated_token_account::DevnetSplAssociatedTokenAccountExec
pub use self::spl::associated_token_account::DevnetSplAssociatedTokenAccountExecutionSummary;
/// Executes one Devnet Associated Token Account simulation or authorized submission.
pub use self::spl::associated_token_account::execute_devnet_spl_associated_token_account;
/// Executes one ATA operation with an explicitly resolved wallet capability.
pub use self::spl::associated_token_account::execute_devnet_spl_associated_token_account_with_wallet;
/// Simulates one Devnet Associated Token Account operation after stateful preflight.
pub use self::spl::associated_token_account::simulate_devnet_spl_associated_token_account;
/// Complete request for one SPL Memo v4 Devnet execution.
@@ -255,6 +290,8 @@ pub use self::spl::memo::DevnetMemoExecutionRequest;
pub use self::spl::memo::DevnetMemoExecutionSummary;
/// Executes one SPL Memo v4 Devnet simulation or explicitly authorized submission.
pub use self::spl::memo::execute_devnet_memo;
/// Executes one Memo operation with an explicitly resolved wallet capability.
pub use self::spl::memo::execute_devnet_memo_with_wallet;
/// Complete request for one Devnet classic SPL Token execution.
pub use self::spl::token::execution::DevnetSplTokenExecutionRequest;
/// Complete result of one Devnet classic SPL Token execution.
@@ -265,6 +302,8 @@ pub(crate) use self::spl::token::execution::canonical_available;
pub(crate) use self::spl::token::execution::decode_completed;
/// Executes one Devnet classic SPL Token simulation or authorized submission.
pub use self::spl::token::execution::execute_devnet_spl_token;
/// Executes one SPL Token operation with an explicitly resolved wallet capability.
pub use self::spl::token::execution::execute_devnet_spl_token_with_wallet;
/// Canonical signature hydration helper shared by Token lifecycle orchestration.
pub(crate) use self::spl::token::execution::hydrate_signature;
/// Targeted program replay helper shared by Token lifecycle orchestration.
@@ -293,6 +332,8 @@ pub use self::spl::token_2022::devnet_execution::DevnetSplToken2022ExecutionRequ
pub use self::spl::token_2022::devnet_execution::DevnetSplToken2022ExecutionSummary;
/// Executes one Devnet Token-2022 simulation or authorized submission.
pub use self::spl::token_2022::devnet_execution::execute_devnet_spl_token_2022;
/// Executes one Token-2022 operation with an explicitly resolved wallet capability.
pub use self::spl::token_2022::devnet_execution::execute_devnet_spl_token_2022_with_wallet;
/// Simulates one Devnet Token-2022 operation after stateful preflight.
pub use self::spl::token_2022::devnet_execution::simulate_devnet_spl_token_2022;
/// Stable category of one independent Devnet validation scenario.
@@ -323,6 +364,8 @@ pub use self::spl::token_2022::metadata::campaign::DevnetToken2022MetadataCampai
pub use self::spl::token_2022::metadata::campaign::DevnetToken2022MetadataCampaignSummary;
/// Executes all five Token Metadata interface instructions on one fresh Devnet mint.
pub use self::spl::token_2022::metadata::campaign::execute_devnet_token_2022_metadata_campaign;
/// Executes the Token Metadata campaign with an explicitly resolved wallet.
pub use self::spl::token_2022::metadata::campaign::execute_devnet_token_2022_metadata_campaign_with_wallet;
/// Returns the exact ordered operation names covered by the Token Metadata campaign.
pub use self::spl::token_2022::metadata::campaign::token_2022_metadata_campaign_operation_names;
/// Additional metadata key created and removed by the campaign.
@@ -341,6 +384,8 @@ pub use self::spl::token_2022::metadata::fixture::Token2022MetadataFixturePrepar
pub use self::spl::token_2022::metadata::fixture::Token2022MetadataFixturePreparationSummary;
/// Creates one fresh Token-2022 mint with a self-referential Metadata Pointer.
pub use self::spl::token_2022::metadata::fixture::prepare_token_2022_metadata_fixture;
/// Creates the Token-2022 metadata fixture with an explicitly resolved wallet.
pub use self::spl::token_2022::metadata::fixture::prepare_token_2022_metadata_fixture_with_wallet;
/// Maximum evidence entries retained by one Token Metadata validation scenario.
pub use self::spl::token_2022::metadata::validation::MAX_TOKEN_2022_METADATA_VALIDATION_EVIDENCE;
/// One bounded evidence item retained by the Token Metadata validation matrix.
@@ -377,6 +422,10 @@ pub use self::spl::token_2022::validation::load_token_2022_validation_matrix;
pub use self::spl::token_2022::validation::validate_token_2022_validation_matrix;
/// Validates one bounded Token-2022 milestone report.
pub use self::spl::token_2022::validation::validate_token_2022_validation_report;
/// Resolved temporary or persistent signer capability used by Devnet scenarios.
pub use self::wallet::DevnetExecutionWallet;
/// Resolves the wallet selected by one Devnet execution profile.
pub use self::wallet::resolve_devnet_execution_wallet;
/// Total transactions reserved by one complete Solana Program Metadata campaign.
pub(crate) use self::constants::SOLANA_PROGRAM_METADATA_CAMPAIGN_TRANSACTION_COUNT;

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/collection_verify_campaign.rs
// version: 6
// version: 7
//! Confirmed Devnet collection parent/member `Verify -> Unverify` campaign.
@@ -50,6 +50,34 @@ pub async fn execute_devnet_metaplex_collection_verify_campaign<S, O>(
options: &crate::MetaplexCreateFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexCollectionVerifyCampaignSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
+ ks_store::DecodePipelineStore
+ Sync,
O: crate::SolanaExecutionObserver,
{
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return execute_devnet_metaplex_collection_verify_campaign_with_wallet(
http_pool, store, profile, &wallet, options, observer,
)
.await;
}
/// Executes one collection verification campaign with an explicit operator wallet.
#[allow(clippy::too_many_arguments)]
pub async fn execute_devnet_metaplex_collection_verify_campaign_with_wallet<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
options: &crate::MetaplexCreateFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexCollectionVerifyCampaignSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
@@ -65,11 +93,11 @@ where
let mut parent_options = options.clone();
parent_options.asset_family = crate::MetaplexTokenMetadataAssetFamily::Collection;
parent_options.collection_mint = std::option::Option::None;
let parent = match crate::execute_devnet_metaplex_create_mint_campaign(
let parent = match crate::execute_devnet_metaplex_create_mint_campaign_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&parent_options,
observer,
)
@@ -81,11 +109,11 @@ where
let mut member_options = options.clone();
member_options.asset_family = crate::MetaplexTokenMetadataAssetFamily::Nft;
member_options.collection_mint = std::option::Option::Some(parent.fixture.mint.clone());
let member = match crate::execute_devnet_metaplex_create_mint_campaign(
let member = match crate::execute_devnet_metaplex_create_mint_campaign_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&member_options,
observer,
)
@@ -168,11 +196,11 @@ where
options.query_role.as_str(),
std::option::Option::Some(fixture_slot),
);
let verify = match crate::execute_devnet_metaplex_token_metadata(
let verify = match crate::execute_devnet_metaplex_token_metadata_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&verify_request,
decoders.as_slice(),
materializers.as_slice(),
@@ -240,11 +268,11 @@ where
options.query_role.as_str(),
std::option::Option::Some(verify_slot),
);
let unverify = match crate::execute_devnet_metaplex_token_metadata(
let unverify = match crate::execute_devnet_metaplex_token_metadata_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&unverify_request,
decoders.as_slice(),
materializers.as_slice(),
@@ -667,7 +695,8 @@ mod tests {
if let std::result::Result::Err(error) = store.initialize_store_schema().await {
panic!("PostgreSQL schema initialization failed: {error}");
}
let configured_wallet_dir = std::path::PathBuf::from(profile.wallet.wallet_dir.as_str());
let configured_wallet_dir =
std::path::PathBuf::from(profile.wallet.temporary_wallet_dir.as_str());
let wallet_dir = if configured_wallet_dir.is_absolute() {
configured_wallet_dir
} else {

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/create_mint_campaign.rs
// version: 14
// version: 15
//! Confirmed Devnet `Create -> Mint` campaign for one Metaplex asset family.
@@ -52,6 +52,34 @@ pub async fn execute_devnet_metaplex_create_mint_campaign<S, O>(
options: &crate::MetaplexCreateFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexCreateMintCampaignSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
+ ks_store::DecodePipelineStore
+ Sync,
O: crate::SolanaExecutionObserver,
{
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return execute_devnet_metaplex_create_mint_campaign_with_wallet(
http_pool, store, profile, &wallet, options, observer,
)
.await;
}
/// Executes one fresh family-specific `Create -> Mint` campaign with an explicit operator wallet.
#[allow(clippy::too_many_arguments)]
pub async fn execute_devnet_metaplex_create_mint_campaign_with_wallet<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
options: &crate::MetaplexCreateFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexCreateMintCampaignSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
@@ -64,13 +92,14 @@ where
"Metaplex Create -> Mint Devnet campaign requires devnet_send_enabled=true",
));
}
let fixture =
match crate::prepare_metaplex_create_fixture(http_pool, profile, workspace_root, options)
.await
{
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let fixture = match crate::prepare_metaplex_create_fixture_with_wallet(
http_pool, profile, wallet, options,
)
.await
{
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let decoders: std::vec::Vec<std::sync::Arc<dyn ks_lib::DcApiInstructionDecoder>> =
std::vec![std::sync::Arc::new(ks_lib::DcMetadataMetaplexTokenMetadataDecoder)];
let materializers: std::vec::Vec<std::sync::Arc<dyn ks_lib::MtApiEventMaterializer>> = std::vec![
@@ -100,11 +129,11 @@ where
std::option::Option::None,
false,
);
let create = match crate::execute_devnet_metaplex_token_metadata(
let create = match crate::execute_devnet_metaplex_token_metadata_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&create_request,
decoders.as_slice(),
materializers.as_slice(),
@@ -239,11 +268,11 @@ where
std::option::Option::Some(create_slot),
true,
);
let mint = match crate::execute_devnet_metaplex_token_metadata(
let mint = match crate::execute_devnet_metaplex_token_metadata_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&mint_request,
decoders.as_slice(),
materializers.as_slice(),
@@ -832,7 +861,8 @@ mod tests {
if let std::result::Result::Err(error) = store.initialize_store_schema().await {
panic!("PostgreSQL schema initialization failed: {error}");
}
let configured_wallet_dir = std::path::PathBuf::from(profile.wallet.wallet_dir.as_str());
let configured_wallet_dir =
std::path::PathBuf::from(profile.wallet.temporary_wallet_dir.as_str());
let wallet_dir = if configured_wallet_dir.is_absolute() {
configured_wallet_dir
} else {

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/devnet_execution.rs
// version: 23
// version: 24
//! Real Devnet simulation and submission for current Metaplex Token Metadata operations.
@@ -363,7 +363,6 @@ pub struct DevnetMetaplexTokenMetadataExecutionSummary {
}
struct PreparedMetaplexExecution {
wallet: ks_wallet::TemporaryWallet,
unsigned: ks_lib::ExSolanaUnsignedTransaction,
evidence: ks_lib::ExSolanaSimulationEvidence,
summary: crate::DevnetMetaplexTokenMetadataExecutionSummary,
@@ -377,6 +376,28 @@ pub async fn simulate_devnet_metaplex_token_metadata<O>(
request: &crate::DevnetMetaplexTokenMetadataExecutionRequest,
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexTokenMetadataExecutionSummary>
where
O: crate::SolanaExecutionObserver,
{
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return simulate_devnet_metaplex_token_metadata_with_wallet(
http_pool, profile, &wallet, request, observer,
)
.await;
}
/// Simulates one current Metaplex operation with an explicitly resolved wallet.
pub async fn simulate_devnet_metaplex_token_metadata_with_wallet<O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
request: &crate::DevnetMetaplexTokenMetadataExecutionRequest,
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexTokenMetadataExecutionSummary>
where
O: crate::SolanaExecutionObserver,
{
@@ -385,11 +406,11 @@ where
"simulate_devnet_metaplex_token_metadata requires submit=false",
));
}
let prepared =
match prepare_execution(http_pool, profile, workspace_root, request, &[], observer).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let prepared = match prepare_execution(http_pool, profile, wallet, request, &[], observer).await
{
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
return std::result::Result::Ok(prepared.summary);
}
@@ -412,11 +433,48 @@ where
+ Sync,
O: crate::SolanaExecutionObserver,
{
return crate::execute_devnet_metaplex_token_metadata_with_signers(
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return execute_devnet_metaplex_token_metadata_with_wallet(
http_pool,
store,
profile,
workspace_root,
&wallet,
request,
decoders,
materializers,
observer,
)
.await;
}
/// Executes one real Devnet Metaplex operation with an explicitly resolved wallet.
#[allow(clippy::too_many_arguments)]
pub async fn execute_devnet_metaplex_token_metadata_with_wallet<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
request: &crate::DevnetMetaplexTokenMetadataExecutionRequest,
decoders: &[std::sync::Arc<dyn ks_lib::DcApiInstructionDecoder>],
materializers: &[std::sync::Arc<dyn ks_lib::MtApiEventMaterializer>],
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexTokenMetadataExecutionSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
+ ks_store::DecodePipelineStore
+ Sync,
O: crate::SolanaExecutionObserver,
{
return execute_devnet_metaplex_token_metadata_with_wallet_and_signers(
http_pool,
store,
profile,
wallet,
request,
decoders,
materializers,
@@ -446,19 +504,52 @@ where
+ Sync,
O: crate::SolanaExecutionObserver,
{
let prepared = match prepare_execution(
http_pool,
profile,
workspace_root,
request,
additional_signers,
observer,
)
.await
{
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return execute_devnet_metaplex_token_metadata_with_wallet_and_signers(
http_pool,
store,
profile,
&wallet,
request,
decoders,
materializers,
additional_signers,
observer,
)
.await;
}
/// Executes one real Devnet Metaplex submission with an explicit wallet and extra signers.
#[allow(clippy::too_many_arguments)]
pub async fn execute_devnet_metaplex_token_metadata_with_wallet_and_signers<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
request: &crate::DevnetMetaplexTokenMetadataExecutionRequest,
decoders: &[std::sync::Arc<dyn ks_lib::DcApiInstructionDecoder>],
materializers: &[std::sync::Arc<dyn ks_lib::MtApiEventMaterializer>],
additional_signers: &[&(dyn solana_signer::Signer + std::marker::Sync)],
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexTokenMetadataExecutionSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
+ ks_store::DecodePipelineStore
+ Sync,
O: crate::SolanaExecutionObserver,
{
let prepared =
match prepare_execution(http_pool, profile, wallet, request, additional_signers, observer)
.await
{
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
if !request.submit {
return std::result::Result::Ok(prepared.summary);
}
@@ -483,7 +574,7 @@ where
let signed = match sign_prepared_transaction(
prepared.unsigned,
&prepared.evidence,
prepared.wallet.as_sync_signer(),
wallet.as_sync_signer(),
additional_signers,
) {
std::result::Result::Ok(value) => value,
@@ -805,7 +896,7 @@ fn replay_summary_diagnostic(
async fn prepare_execution<O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
profile: &ks_config::ProfileConfig,
workspace_root: &std::path::Path,
wallet: &crate::DevnetExecutionWallet,
request: &crate::DevnetMetaplexTokenMetadataExecutionRequest,
additional_signers: &[&(dyn solana_signer::Signer + std::marker::Sync)],
observer: &O,
@@ -839,11 +930,7 @@ where
),
));
}
let wallet = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet_summary = wallet.summary();
let wallet_summary = wallet.identity();
let fee_payer = ks_lib::MdPubkey(wallet_summary.public_key.clone());
let balance = match http_pool
.get_balance_for_role(
@@ -1000,7 +1087,6 @@ where
};
let evidence = unsigned.bind_simulation(simulation.clone());
return std::result::Result::Ok(PreparedMetaplexExecution {
wallet,
unsigned,
evidence,
summary: crate::DevnetMetaplexTokenMetadataExecutionSummary {
@@ -1175,9 +1261,11 @@ fn validate_profile(
"Metaplex Devnet orchestration requires a Devnet wallet profile",
));
}
if !profile.wallet.temporary_wallet_enabled || !profile.wallet.temporary_wallet_persist {
if profile.wallet.wallet_alias.is_none()
&& (!profile.wallet.temporary_wallet_enabled || !profile.wallet.temporary_wallet_persist)
{
return std::result::Result::Err(ks_core::Error::config(
"Metaplex Devnet orchestration requires an enabled persistent temporary wallet",
"Metaplex Devnet orchestration requires an enabled persistent temporary wallet when no native wallet alias is selected",
));
}
if !profile.execution.require_simulation {
@@ -1416,7 +1504,7 @@ mod tests {
};
let mut profile = example_devnet_profile();
if let std::result::Result::Ok(directory) = std::env::var("KS_DEVNET_WALLET_DIR") {
profile.wallet.wallet_dir = directory;
profile.wallet.temporary_wallet_dir = directory;
}
let pool = match ks_onchain_transport::HttpEndpointPool::from_profile(&profile) {
std::result::Result::Ok(value) => value,

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/escrow_campaign.rs
// version: 6
// version: 7
//! Confirmed Devnet Token Owned Escrow campaign for current Metaplex escrow operations.
@@ -64,6 +64,34 @@ pub async fn execute_devnet_metaplex_escrow_campaign<S, O>(
options: &crate::MetaplexCreateFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexEscrowCampaignSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
+ ks_store::DecodePipelineStore
+ Sync,
O: crate::SolanaExecutionObserver,
{
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return execute_devnet_metaplex_escrow_campaign_with_wallet(
http_pool, store, profile, &wallet, options, observer,
)
.await;
}
/// Executes a fresh Token Owned Escrow lifecycle with an explicit operator wallet.
#[allow(clippy::too_many_arguments)]
pub async fn execute_devnet_metaplex_escrow_campaign_with_wallet<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
options: &crate::MetaplexCreateFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexEscrowCampaignSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
@@ -80,11 +108,11 @@ where
clean_fixture_options(options, crate::MetaplexTokenMetadataAssetFamily::Nft);
let attribute_options =
clean_fixture_options(options, crate::MetaplexTokenMetadataAssetFamily::Fungible);
let parent_fixture = match crate::execute_devnet_metaplex_create_mint_campaign(
let parent_fixture = match crate::execute_devnet_metaplex_create_mint_campaign_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&parent_options,
observer,
)
@@ -93,11 +121,11 @@ where
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let attribute_fixture = match crate::execute_devnet_metaplex_create_mint_campaign(
let attribute_fixture = match crate::execute_devnet_metaplex_create_mint_campaign_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&attribute_options,
observer,
)
@@ -148,11 +176,11 @@ where
parent_options.query_role.as_str(),
std::option::Option::None,
);
let create_escrow = match crate::execute_devnet_metaplex_token_metadata(
let create_escrow = match crate::execute_devnet_metaplex_token_metadata_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&create_request,
metaplex_decoders.as_slice(),
metaplex_materializers.as_slice(),
@@ -195,21 +223,22 @@ where
ata_request.submit = true;
ata_request.operator_confirmed = true;
ata_request.post_validation_max_retries = 20;
let escrow_attribute_ata_creation = match crate::execute_devnet_spl_associated_token_account(
http_pool,
store,
profile,
workspace_root,
&ata_request,
ata_decoders.as_slice(),
ata_materializers.as_slice(),
observer,
)
.await
{
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let escrow_attribute_ata_creation =
match crate::execute_devnet_spl_associated_token_account_with_wallet(
http_pool,
store,
profile,
wallet,
&ata_request,
ata_decoders.as_slice(),
ata_materializers.as_slice(),
observer,
)
.await
{
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let ata_slot = match validate_ata_setup(&escrow_attribute_ata_creation) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
@@ -271,11 +300,11 @@ where
deposit_request.submit = true;
deposit_request.operator_confirmed = true;
deposit_request.post_validation_max_retries = 20;
let attribute_deposit = match crate::execute_devnet_spl_token(
let attribute_deposit = match crate::execute_devnet_spl_token_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&deposit_request,
token_decoders.as_slice(),
token_materializers.as_slice(),
@@ -357,11 +386,11 @@ where
parent_options.query_role.as_str(),
std::option::Option::Some(deposit_slot),
);
let transfer_out = match crate::execute_devnet_metaplex_token_metadata(
let transfer_out = match crate::execute_devnet_metaplex_token_metadata_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&transfer_request,
metaplex_decoders.as_slice(),
metaplex_materializers.as_slice(),
@@ -443,11 +472,11 @@ where
parent_options.query_role.as_str(),
std::option::Option::Some(transfer_slot),
);
let close_escrow = match crate::execute_devnet_metaplex_token_metadata(
let close_escrow = match crate::execute_devnet_metaplex_token_metadata_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&close_request,
metaplex_decoders.as_slice(),
metaplex_materializers.as_slice(),
@@ -992,7 +1021,8 @@ mod tests {
if let std::result::Result::Err(error) = store.initialize_store_schema().await {
panic!("PostgreSQL schema initialization failed: {error}");
}
let configured_wallet_dir = std::path::PathBuf::from(profile.wallet.wallet_dir.as_str());
let configured_wallet_dir =
std::path::PathBuf::from(profile.wallet.temporary_wallet_dir.as_str());
let wallet_dir = if configured_wallet_dir.is_absolute() {
configured_wallet_dir
} else {

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/fixture.rs
// version: 22
// version: 23
//! Native Metaplex Token Metadata fixture preparation for Devnet demos.
@@ -114,6 +114,21 @@ pub async fn prepare_metaplex_create_fixture(
profile: &ks_config::ProfileConfig,
workspace_root: &std::path::Path,
options: &crate::MetaplexCreateFixturePreparationOptions,
) -> ks_core::Result<crate::MetaplexCreateFixturePreparationSummary> {
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return prepare_metaplex_create_fixture_with_wallet(http_pool, profile, &wallet, options).await;
}
/// Creates one family-consistent classic SPL mint using an explicitly resolved operator wallet.
pub async fn prepare_metaplex_create_fixture_with_wallet(
http_pool: &ks_onchain_transport::HttpEndpointPool,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
options: &crate::MetaplexCreateFixturePreparationOptions,
) -> ks_core::Result<crate::MetaplexCreateFixturePreparationSummary> {
if options.query_role.trim().is_empty() || options.transaction_role.trim().is_empty() {
return std::result::Result::Err(ks_core::Error::config(
@@ -168,10 +183,6 @@ pub async fn prepare_metaplex_create_fixture(
return std::result::Result::Err(error);
}
}
let operator = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let fixture_dir = options.wallet_dir.join("metaplex_token_metadata_validation");
let fixture_store = match ks_wallet::TemporaryWalletStore::new(fixture_dir.clone()) {
std::result::Result::Ok(value) => value,
@@ -196,7 +207,7 @@ pub async fn prepare_metaplex_create_fixture(
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let mint_keypair_path = fixture_store.wallet_path(&fixture_alias);
let authority = operator.public_key();
let authority = wallet.public_key();
let mint = mint_wallet.public_key();
let mint_decimals = fixture_mint_decimals(options.asset_family);
let existing =
@@ -216,7 +227,7 @@ pub async fn prepare_metaplex_create_fixture(
http_pool,
profile,
options,
&operator,
wallet,
&mint_wallet,
mint_decimals,
)
@@ -404,7 +415,7 @@ async fn create_native_classic_mint(
http_pool: &ks_onchain_transport::HttpEndpointPool,
profile: &ks_config::ProfileConfig,
options: &crate::MetaplexCreateFixturePreparationOptions,
operator: &ks_wallet::TemporaryWallet,
operator: &crate::DevnetExecutionWallet,
mint_wallet: &ks_wallet::TemporaryWallet,
mint_decimals: u8,
) -> ks_core::Result<NativeFixturePreparationEvidence> {

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/maintenance_campaign.rs
// version: 8
// version: 9
//! Final bounded Devnet qualification campaign for current Metaplex maintenance operations.
@@ -42,6 +42,34 @@ pub async fn execute_devnet_metaplex_maintenance_campaign<S, O>(
options: &crate::MetaplexCreateFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexMaintenanceCampaignSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
+ ks_store::DecodePipelineStore
+ Sync,
O: crate::SolanaExecutionObserver,
{
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return execute_devnet_metaplex_maintenance_campaign_with_wallet(
http_pool, store, profile, &wallet, options, observer,
)
.await;
}
/// Executes the bounded Metaplex maintenance campaign with an explicit operator wallet.
#[allow(clippy::too_many_arguments)]
pub async fn execute_devnet_metaplex_maintenance_campaign_with_wallet<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
options: &crate::MetaplexCreateFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexMaintenanceCampaignSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
@@ -54,13 +82,8 @@ where
"Metaplex maintenance campaign requires the classic NFT fixture family",
));
}
let fixture = match crate::execute_devnet_metaplex_create_mint_campaign(
http_pool,
store,
profile,
workspace_root,
options,
observer,
let fixture = match crate::execute_devnet_metaplex_create_mint_campaign_with_wallet(
http_pool, store, profile, wallet, options, observer,
)
.await
{
@@ -91,7 +114,7 @@ where
http_pool,
store,
profile,
workspace_root,
wallet,
options,
observer,
)
@@ -130,7 +153,7 @@ where
201,
http_pool,
profile,
workspace_root,
wallet,
options,
observer,
)
@@ -145,7 +168,7 @@ where
75,
http_pool,
profile,
workspace_root,
wallet,
options,
observer,
)
@@ -163,7 +186,7 @@ where
7,
http_pool,
profile,
workspace_root,
wallet,
options,
observer,
)
@@ -184,7 +207,7 @@ where
188,
http_pool,
profile,
workspace_root,
wallet,
options,
observer,
)
@@ -272,7 +295,7 @@ async fn execute_confirmed_operation<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
workspace_root: &std::path::Path,
wallet: &crate::DevnetExecutionWallet,
options: &crate::MetaplexCreateFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexTokenMetadataExecutionSummary>
@@ -304,11 +327,11 @@ where
request.operator_confirmed = true;
request.materialize_after_confirmation = true;
request.post_validation_max_retries = 20;
return crate::execute_devnet_metaplex_token_metadata(
return crate::execute_devnet_metaplex_token_metadata_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&request,
decoders.as_slice(),
materializers.as_slice(),
@@ -324,7 +347,7 @@ async fn simulate_expected_unavailable<O>(
expected_custom_error: u64,
http_pool: &ks_onchain_transport::HttpEndpointPool,
profile: &ks_config::ProfileConfig,
workspace_root: &std::path::Path,
wallet: &crate::DevnetExecutionWallet,
options: &crate::MetaplexCreateFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexTokenMetadataExecutionSummary>
@@ -337,12 +360,8 @@ where
);
request.query_role = options.query_role.clone();
request.transaction_role = options.transaction_role.clone();
let summary = match crate::simulate_devnet_metaplex_token_metadata(
http_pool,
profile,
workspace_root,
&request,
observer,
let summary = match crate::simulate_devnet_metaplex_token_metadata_with_wallet(
http_pool, profile, wallet, &request, observer,
)
.await
{
@@ -596,7 +615,8 @@ mod tests {
if let std::result::Result::Err(error) = store.initialize_store_schema().await {
panic!("PostgreSQL schema initialization failed: {error}");
}
let configured_wallet_dir = std::path::PathBuf::from(profile.wallet.wallet_dir.as_str());
let configured_wallet_dir =
std::path::PathBuf::from(profile.wallet.temporary_wallet_dir.as_str());
let wallet_dir = if configured_wallet_dir.is_absolute() {
configured_wallet_dir
} else {

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/pnft_lifecycle_campaign.rs
// version: 8
// version: 10
//! Confirmed Devnet pNFT delegate, lock, unlock, revoke and transfer campaign.
@@ -76,6 +76,34 @@ pub async fn execute_devnet_metaplex_pnft_lifecycle_campaign<S, O>(
options: &crate::MetaplexCreateFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexPnftLifecycleCampaignSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
+ ks_store::DecodePipelineStore
+ Sync,
O: crate::SolanaExecutionObserver,
{
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return execute_devnet_metaplex_pnft_lifecycle_campaign_with_wallet(
http_pool, store, profile, &wallet, options, observer,
)
.await;
}
/// Executes one fresh pNFT lifecycle campaign with an explicit operator wallet.
#[allow(clippy::too_many_arguments)]
pub async fn execute_devnet_metaplex_pnft_lifecycle_campaign_with_wallet<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
options: &crate::MetaplexCreateFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexPnftLifecycleCampaignSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
@@ -88,13 +116,8 @@ where
"Metaplex pNFT lifecycle campaign requires asset_family=programmable_nft",
));
}
let pnft = match crate::execute_devnet_metaplex_create_mint_campaign(
http_pool,
store,
profile,
workspace_root,
options,
observer,
let pnft = match crate::execute_devnet_metaplex_create_mint_campaign_with_wallet(
http_pool, store, profile, wallet, options, observer,
)
.await
{
@@ -205,7 +228,7 @@ where
http_pool,
store,
profile,
workspace_root,
wallet,
options,
"delegate-staking",
delegate_staking_operation,
@@ -261,7 +284,7 @@ where
http_pool,
store,
profile,
workspace_root,
wallet,
options,
"lock",
lock_operation,
@@ -322,7 +345,7 @@ where
http_pool,
store,
profile,
workspace_root,
wallet,
options,
"unlock",
unlock_operation,
@@ -378,7 +401,7 @@ where
http_pool,
store,
profile,
workspace_root,
wallet,
options,
"revoke-staking",
revoke_operation,
@@ -436,7 +459,7 @@ where
http_pool,
store,
profile,
workspace_root,
wallet,
options,
"delegate-transfer",
delegate_transfer_operation,
@@ -495,7 +518,7 @@ where
http_pool,
store,
profile,
workspace_root,
wallet,
options,
transfer_operation,
destination.1.as_str(),
@@ -631,7 +654,7 @@ async fn execute_profile_step<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
workspace_root: &std::path::Path,
wallet: &crate::DevnetExecutionWallet,
options: &crate::MetaplexCreateFixturePreparationOptions,
label: &str,
operation: ks_lib::ExMetaplexTokenMetadataOperation,
@@ -654,11 +677,11 @@ where
request.operator_confirmed = true;
request.materialize_after_confirmation = true;
request.post_validation_max_retries = 20;
return crate::execute_devnet_metaplex_token_metadata(
return crate::execute_devnet_metaplex_token_metadata_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&request,
decoders,
materializers,
@@ -672,7 +695,7 @@ async fn execute_delegate_step<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
workspace_root: &std::path::Path,
wallet: &crate::DevnetExecutionWallet,
options: &crate::MetaplexCreateFixturePreparationOptions,
label: &str,
operation: ks_lib::ExMetaplexTokenMetadataOperation,
@@ -698,11 +721,11 @@ where
request.post_validation_max_retries = 20;
request.additional_authorized_signers =
std::vec![ks_lib::MdPubkey(delegate_wallet.public_key())];
return crate::execute_devnet_metaplex_token_metadata_with_signers(
return crate::execute_devnet_metaplex_token_metadata_with_wallet_and_signers(
http_pool,
store,
profile,
workspace_root,
wallet,
&request,
decoders,
materializers,
@@ -717,7 +740,7 @@ async fn execute_delegate_transfer_step<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
workspace_root: &std::path::Path,
wallet: &crate::DevnetExecutionWallet,
options: &crate::MetaplexCreateFixturePreparationOptions,
operation: ks_lib::ExMetaplexTokenMetadataOperation,
destination_token_record: &str,
@@ -749,11 +772,11 @@ where
request.post_validation_max_retries = 20;
request.additional_authorized_signers =
std::vec![ks_lib::MdPubkey(delegate_wallet.public_key())];
return crate::execute_devnet_metaplex_token_metadata_with_signers(
return crate::execute_devnet_metaplex_token_metadata_with_wallet_and_signers(
http_pool,
store,
profile,
workspace_root,
wallet,
&request,
decoders,
materializers,
@@ -1090,7 +1113,8 @@ mod tests {
if let std::result::Result::Err(error) = store.initialize_store_schema().await {
panic!("PostgreSQL schema initialization failed: {error}");
}
let configured_wallet_dir = std::path::PathBuf::from(profile.wallet.wallet_dir.as_str());
let configured_wallet_dir =
std::path::PathBuf::from(profile.wallet.temporary_wallet_dir.as_str());
let wallet_dir = if configured_wallet_dir.is_absolute() {
configured_wallet_dir
} else {

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/print_burn_campaign.rs
// version: 9
// version: 10
//! Devnet printable master NFT `Print -> Burn` campaign.
@@ -84,6 +84,34 @@ pub async fn execute_devnet_metaplex_print_burn_campaign<S, O>(
options: &crate::MetaplexCreateFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexPrintBurnCampaignSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
+ ks_store::DecodePipelineStore
+ Sync,
O: crate::SolanaExecutionObserver,
{
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return execute_devnet_metaplex_print_burn_campaign_with_wallet(
http_pool, store, profile, &wallet, options, observer,
)
.await;
}
/// Executes one printable master NFT `Print -> Burn` campaign with an explicit operator wallet.
#[allow(clippy::too_many_arguments)]
pub async fn execute_devnet_metaplex_print_burn_campaign_with_wallet<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
options: &crate::MetaplexCreateFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexPrintBurnCampaignSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
@@ -100,11 +128,11 @@ where
master_options.asset_family = crate::MetaplexTokenMetadataAssetFamily::Nft;
master_options.collection_mint = std::option::Option::None;
master_options.print_supply_limit = std::option::Option::Some(1);
let master = match crate::execute_devnet_metaplex_create_mint_campaign(
let master = match crate::execute_devnet_metaplex_create_mint_campaign_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&master_options,
observer,
)
@@ -329,11 +357,11 @@ where
options.query_role.as_str(),
std::option::Option::Some(master_mint_slot),
);
let print = match crate::execute_devnet_metaplex_token_metadata_with_signers(
let print = match crate::execute_devnet_metaplex_token_metadata_with_wallet_and_signers(
http_pool,
store,
profile,
workspace_root,
wallet,
&print_request,
decoders.as_slice(),
materializers.as_slice(),
@@ -498,11 +526,11 @@ where
options.query_role.as_str(),
std::option::Option::Some(print_slot),
);
let burn = match crate::execute_devnet_metaplex_token_metadata(
let burn = match crate::execute_devnet_metaplex_token_metadata_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&burn_request,
decoders.as_slice(),
materializers.as_slice(),
@@ -1199,7 +1227,8 @@ mod tests {
if let std::result::Result::Err(error) = store.initialize_store_schema().await {
panic!("PostgreSQL schema initialization failed: {error}");
}
let configured_wallet_dir = std::path::PathBuf::from(profile.wallet.wallet_dir.as_str());
let configured_wallet_dir =
std::path::PathBuf::from(profile.wallet.temporary_wallet_dir.as_str());
let wallet_dir = if configured_wallet_dir.is_absolute() {
configured_wallet_dir
} else {

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/metaplex_token_metadata/use_campaign.rs
// version: 6
// version: 7
//! Bounded Devnet availability probe for the current Metaplex `Use` surface.
@@ -46,6 +46,34 @@ pub async fn execute_devnet_metaplex_use_probe<S, O>(
options: &crate::MetaplexCreateFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexUseProbeSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
+ ks_store::DecodePipelineStore
+ Sync,
O: crate::SolanaExecutionObserver,
{
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return execute_devnet_metaplex_use_probe_with_wallet(
http_pool, store, profile, &wallet, options, observer,
)
.await;
}
/// Executes one fresh classic NFT `Use` probe with an explicit operator wallet.
#[allow(clippy::too_many_arguments)]
pub async fn execute_devnet_metaplex_use_probe_with_wallet<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
options: &crate::MetaplexCreateFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetMetaplexUseProbeSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
@@ -59,11 +87,11 @@ where
));
}
let fixture_options = options.clone().with_multiple_uses(2);
let fixture = match crate::execute_devnet_metaplex_create_mint_campaign(
let fixture = match crate::execute_devnet_metaplex_create_mint_campaign_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&fixture_options,
observer,
)
@@ -93,10 +121,10 @@ where
);
simulation_request.query_role = fixture_options.query_role.clone();
simulation_request.transaction_role = fixture_options.transaction_role.clone();
let simulation = match crate::simulate_devnet_metaplex_token_metadata(
let simulation = match crate::simulate_devnet_metaplex_token_metadata_with_wallet(
http_pool,
profile,
workspace_root,
wallet,
&simulation_request,
observer,
)
@@ -139,11 +167,11 @@ where
execution_request.post_validation_max_retries = 20;
execution_request.postcondition_reads =
metadata_read(fixture.fixture.metadata.as_str(), fixture_options.query_role.as_str());
let execution = match crate::execute_devnet_metaplex_token_metadata(
let execution = match crate::execute_devnet_metaplex_token_metadata_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&execution_request,
decoders.as_slice(),
materializers.as_slice(),
@@ -444,7 +472,8 @@ mod tests {
if let std::result::Result::Err(error) = store.initialize_store_schema().await {
panic!("PostgreSQL schema initialization failed: {error}");
}
let configured_wallet_dir = std::path::PathBuf::from(profile.wallet.wallet_dir.as_str());
let configured_wallet_dir =
std::path::PathBuf::from(profile.wallet.temporary_wallet_dir.as_str());
let wallet_dir = if configured_wallet_dir.is_absolute() {
configured_wallet_dir
} else {

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/solana_program/campaign.rs
// version: 4
// version: 5
//! Ordered confirmed Devnet campaign for all Solana Program Metadata operations.
@@ -36,6 +36,28 @@ pub async fn execute_devnet_solana_program_metadata_campaign<O>(
options: &crate::SolanaProgramMetadataFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetSolanaProgramMetadataCampaignSummary>
where
O: crate::SolanaExecutionObserver,
{
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return execute_devnet_solana_program_metadata_campaign_with_wallet(
http_pool, profile, &wallet, options, observer,
)
.await;
}
/// Executes the complete Solana Program Metadata campaign with an explicitly resolved wallet.
pub async fn execute_devnet_solana_program_metadata_campaign_with_wallet<O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
options: &crate::SolanaProgramMetadataFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetSolanaProgramMetadataCampaignSummary>
where
O: crate::SolanaExecutionObserver,
{
@@ -44,11 +66,8 @@ where
"Solana Program Metadata Devnet campaign requires explicit operator confirmation",
));
}
let fixture = match crate::prepare_solana_program_metadata_fixture(
http_pool,
profile,
workspace_root,
options,
let fixture = match crate::prepare_solana_program_metadata_fixture_with_wallet(
http_pool, profile, wallet, options,
)
.await
{
@@ -63,12 +82,8 @@ where
request.transaction_role = options.transaction_role.clone();
request.submit = true;
request.operator_confirmed = true;
let execution = match crate::execute_devnet_solana_program_metadata(
http_pool,
profile,
workspace_root,
&request,
observer,
let execution = match crate::execute_devnet_solana_program_metadata_with_wallet(
http_pool, profile, wallet, &request, observer,
)
.await
{

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/solana_program/devnet_execution.rs
// version: 5
// version: 6
//! Real Devnet simulation and controlled submission for Solana Program Metadata.
@@ -155,7 +155,6 @@ pub struct DevnetSolanaProgramMetadataExecutionSummary {
}
struct PreparedSolanaProgramMetadataExecution {
wallet: ks_wallet::TemporaryWallet,
unsigned: ks_lib::ExSolanaUnsignedTransaction,
evidence: ks_lib::ExSolanaSimulationEvidence,
summary: crate::DevnetSolanaProgramMetadataExecutionSummary,
@@ -169,6 +168,28 @@ pub async fn simulate_devnet_solana_program_metadata<O>(
request: &crate::DevnetSolanaProgramMetadataExecutionRequest,
observer: &O,
) -> ks_core::Result<crate::DevnetSolanaProgramMetadataExecutionSummary>
where
O: crate::SolanaExecutionObserver,
{
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return simulate_devnet_solana_program_metadata_with_wallet(
http_pool, profile, &wallet, request, observer,
)
.await;
}
/// Simulates one stable Solana Program Metadata operation with an explicitly resolved wallet.
pub async fn simulate_devnet_solana_program_metadata_with_wallet<O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
request: &crate::DevnetSolanaProgramMetadataExecutionRequest,
observer: &O,
) -> ks_core::Result<crate::DevnetSolanaProgramMetadataExecutionSummary>
where
O: crate::SolanaExecutionObserver,
{
@@ -177,11 +198,10 @@ where
"simulate_devnet_solana_program_metadata requires submit=false",
));
}
let prepared =
match prepare_execution(http_pool, profile, workspace_root, request, observer).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let prepared = match prepare_execution(http_pool, profile, wallet, request, observer).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
return std::result::Result::Ok(prepared.summary);
}
@@ -196,11 +216,32 @@ pub async fn execute_devnet_solana_program_metadata<O>(
where
O: crate::SolanaExecutionObserver,
{
let prepared =
match prepare_execution(http_pool, profile, workspace_root, request, observer).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return execute_devnet_solana_program_metadata_with_wallet(
http_pool, profile, &wallet, request, observer,
)
.await;
}
/// Executes one Solana Program Metadata operation with an explicitly resolved wallet.
pub async fn execute_devnet_solana_program_metadata_with_wallet<O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
request: &crate::DevnetSolanaProgramMetadataExecutionRequest,
observer: &O,
) -> ks_core::Result<crate::DevnetSolanaProgramMetadataExecutionSummary>
where
O: crate::SolanaExecutionObserver,
{
let prepared = match prepare_execution(http_pool, profile, wallet, request, observer).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
if !request.submit {
return std::result::Result::Ok(prepared.summary);
}
@@ -230,7 +271,7 @@ where
}
let signed = match prepared
.unsigned
.sign_after_simulation(&prepared.evidence, &[prepared.wallet.as_signer()])
.sign_after_simulation(&prepared.evidence, &[wallet.as_signer()])
{
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
@@ -322,7 +363,7 @@ where
async fn prepare_execution<O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
profile: &ks_config::ProfileConfig,
workspace_root: &std::path::Path,
wallet: &crate::DevnetExecutionWallet,
request: &crate::DevnetSolanaProgramMetadataExecutionRequest,
observer: &O,
) -> ks_core::Result<PreparedSolanaProgramMetadataExecution>
@@ -355,11 +396,7 @@ where
),
));
}
let wallet = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet_summary = wallet.summary();
let wallet_summary = wallet.identity();
let fee_payer = ks_lib::MdPubkey(wallet_summary.public_key.clone());
let balance = match http_pool
.get_balance_for_role(
@@ -518,7 +555,6 @@ where
};
let evidence = unsigned.bind_simulation(simulation.clone());
return std::result::Result::Ok(PreparedSolanaProgramMetadataExecution {
wallet,
unsigned,
evidence,
summary: crate::DevnetSolanaProgramMetadataExecutionSummary {
@@ -625,9 +661,11 @@ fn validate_profile(
"Solana Program Metadata orchestration requires a Devnet wallet profile",
));
}
if !profile.wallet.temporary_wallet_enabled || !profile.wallet.temporary_wallet_persist {
if profile.wallet.wallet_alias.is_none()
&& (!profile.wallet.temporary_wallet_enabled || !profile.wallet.temporary_wallet_persist)
{
return std::result::Result::Err(ks_core::Error::config(
"Solana Program Metadata orchestration requires an enabled persistent temporary wallet",
"Solana Program Metadata orchestration requires an enabled persistent temporary wallet when no native wallet alias is selected",
));
}
if !profile.execution.require_simulation {

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/metadata/solana_program/fixture.rs
// version: 9
// version: 10
//! Native Solana Program Metadata fixture preparation for Devnet journeys.
@@ -111,6 +111,24 @@ pub async fn prepare_solana_program_metadata_fixture(
profile: &ks_config::ProfileConfig,
workspace_root: &std::path::Path,
options: &crate::SolanaProgramMetadataFixturePreparationOptions,
) -> ks_core::Result<crate::SolanaProgramMetadataFixturePreparationSummary> {
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return prepare_solana_program_metadata_fixture_with_wallet(
http_pool, profile, &wallet, options,
)
.await;
}
/// Creates two unique pre-funded PDAs with an explicitly resolved execution wallet.
pub async fn prepare_solana_program_metadata_fixture_with_wallet(
http_pool: &ks_onchain_transport::HttpEndpointPool,
profile: &ks_config::ProfileConfig,
operator: &crate::DevnetExecutionWallet,
options: &crate::SolanaProgramMetadataFixturePreparationOptions,
) -> ks_core::Result<crate::SolanaProgramMetadataFixturePreparationSummary> {
if options.query_role.trim().is_empty() || options.transaction_role.trim().is_empty() {
return std::result::Result::Err(ks_core::Error::config(
@@ -119,8 +137,9 @@ pub async fn prepare_solana_program_metadata_fixture(
}
if profile.wallet.cluster != "devnet"
|| !profile.execution.devnet_send_enabled
|| !profile.wallet.temporary_wallet_enabled
|| !profile.wallet.temporary_wallet_persist
|| (profile.wallet.wallet_alias.is_none()
&& (!profile.wallet.temporary_wallet_enabled
|| !profile.wallet.temporary_wallet_persist))
{
return std::result::Result::Err(ks_core::Error::config(
"Solana Program Metadata fixture requires one persistent send-enabled Devnet profile",
@@ -143,10 +162,6 @@ pub async fn prepare_solana_program_metadata_fixture(
"Solana Program Metadata fixture preparation requires a Devnet endpoint",
));
}
let operator = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let authority = ks_lib::MdPubkey(operator.public_key());
let described_program = ks_lib::MdPubkey(ks_program_ids::SYSTEM_PROGRAM_ID.to_string());
let unique = uuid::Uuid::new_v4().simple().to_string();
@@ -282,7 +297,7 @@ pub async fn prepare_solana_program_metadata_fixture(
http_pool,
profile,
options,
&operator,
operator,
buffer.clone(),
buffer_prefund_lamports,
"buffer",
@@ -296,7 +311,7 @@ pub async fn prepare_solana_program_metadata_fixture(
http_pool,
profile,
options,
&operator,
operator,
metadata.clone(),
metadata_prefund_lamports,
"metadata",
@@ -680,7 +695,7 @@ async fn submit_prefund_transfer(
http_pool: &ks_onchain_transport::HttpEndpointPool,
profile: &ks_config::ProfileConfig,
options: &crate::SolanaProgramMetadataFixturePreparationOptions,
operator: &ks_wallet::TemporaryWallet,
operator: &crate::DevnetExecutionWallet,
recipient: ks_lib::MdPubkey,
lamports: u64,
label: &str,

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/solana.rs
// version: 17
// version: 18
//! Devnet Solana execution orchestration with canonical post-validation.
@@ -260,6 +260,43 @@ pub async fn execute_devnet_system_transfer<S, O>(
materializers: &[std::sync::Arc<dyn ks_lib::MtApiEventMaterializer>],
observer: &O,
) -> ks_core::Result<crate::DevnetSystemTransferSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
+ ks_store::DecodePipelineStore
+ Sync,
O: crate::SolanaExecutionObserver,
{
let temporary = match load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return execute_devnet_system_transfer_with_wallet(
http_pool,
store,
profile,
&wallet,
request,
decoders,
materializers,
observer,
)
.await;
}
/// Executes a bounded Devnet System transfer with an explicitly resolved wallet capability.
#[allow(clippy::too_many_arguments)]
pub async fn execute_devnet_system_transfer_with_wallet<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
request: &crate::DevnetSystemTransferRequest,
decoders: &[std::sync::Arc<dyn ks_lib::DcApiInstructionDecoder>],
materializers: &[std::sync::Arc<dyn ks_lib::MtApiEventMaterializer>],
observer: &O,
) -> ks_core::Result<crate::DevnetSystemTransferSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
@@ -305,11 +342,7 @@ where
if let std::result::Result::Err(error) = cancellation_result {
return std::result::Result::Err(error);
}
let wallet = match load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(wallet) => wallet,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet_summary = wallet.summary();
let wallet_summary = wallet.identity();
let source_pubkey = ks_lib::MdPubkey(wallet_summary.public_key.clone());
if source_pubkey == request.recipient {
return std::result::Result::Err(ks_core::Error::config(
@@ -945,9 +978,11 @@ fn validate_devnet_profile(
profile.name
)));
}
if !profile.wallet.temporary_wallet_enabled || !profile.wallet.temporary_wallet_persist {
if profile.wallet.wallet_alias.is_none()
&& (!profile.wallet.temporary_wallet_enabled || !profile.wallet.temporary_wallet_persist)
{
return std::result::Result::Err(ks_core::Error::config(
"Devnet execution requires an enabled persistent temporary wallet",
"Devnet execution requires an enabled persistent temporary wallet when no native wallet alias is selected",
));
}
if !profile.execution.require_simulation {
@@ -983,7 +1018,7 @@ fn validate_devnet_profile(
return std::result::Result::Ok(());
}
/// Resolves the wallet directory selected by one profile relative to the workspace root.
/// Resolves the persistent native wallet directory selected by one profile.
fn profile_wallet_directory(
profile: &ks_config::ProfileConfig,
workspace_root: &std::path::Path,
@@ -995,6 +1030,18 @@ fn profile_wallet_directory(
return workspace_root.join(configured);
}
/// Resolves the profile-specific temporary wallet and fixture directory.
fn profile_temporary_wallet_directory(
profile: &ks_config::ProfileConfig,
workspace_root: &std::path::Path,
) -> std::path::PathBuf {
let configured = std::path::PathBuf::from(profile.wallet.temporary_wallet_dir.as_str());
if configured.is_absolute() {
return configured;
}
return workspace_root.join(configured);
}
/// Inspects the persistent native wallet alias selected by one profile, when configured.
pub async fn inspect_selected_profile_wallet(
profile: &ks_config::ProfileConfig,
@@ -1065,7 +1112,7 @@ pub(crate) async fn load_profile_temporary_wallet(
"profile selects a persistent native wallet; temporary-wallet fallback is forbidden",
));
}
let store = match ks_wallet::TemporaryWalletStore::new(profile_wallet_directory(
let store = match ks_wallet::TemporaryWalletStore::new(profile_temporary_wallet_directory(
profile,
workspace_root,
)) {
@@ -1500,7 +1547,7 @@ mod tests {
profile.database.backend = "postgres".to_string();
profile.database.postgres.url = database_url;
if let std::result::Result::Ok(directory) = std::env::var("KS_DEVNET_WALLET_DIR") {
profile.wallet.wallet_dir = directory;
profile.wallet.temporary_wallet_dir = directory;
}
let pool = match ks_onchain_transport::HttpEndpointPool::from_profile(&profile) {
std::result::Result::Ok(value) => value,

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/spl/associated_token_account.rs
// version: 16
// version: 17
//! Devnet ATA execution with stateful and canonical post-validation.
@@ -108,7 +108,6 @@ pub struct DevnetSplAssociatedTokenAccountExecutionSummary {
}
struct PreparedAtaExecution {
wallet: ks_wallet::TemporaryWallet,
unsigned: ks_lib::ExSolanaUnsignedTransaction,
evidence: ks_lib::ExSolanaSimulationEvidence,
summary: DevnetSplAssociatedTokenAccountExecutionSummary,
@@ -130,11 +129,15 @@ where
"simulate_devnet_spl_associated_token_account requires submit=false",
));
}
let prepared =
match prepare_execution(http_pool, profile, workspace_root, request, observer).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
let prepared = match prepare_execution(http_pool, profile, &wallet, request, observer).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
return std::result::Result::Ok(prepared.summary);
}
@@ -157,11 +160,47 @@ where
+ Sync,
O: crate::SolanaExecutionObserver,
{
let prepared =
match prepare_execution(http_pool, profile, workspace_root, request, observer).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return execute_devnet_spl_associated_token_account_with_wallet(
http_pool,
store,
profile,
&wallet,
request,
decoders,
materializers,
observer,
)
.await;
}
/// Executes this Devnet operation with an explicitly resolved wallet capability.
#[allow(clippy::too_many_arguments)]
pub async fn execute_devnet_spl_associated_token_account_with_wallet<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
request: &DevnetSplAssociatedTokenAccountExecutionRequest,
decoders: &[std::sync::Arc<dyn ks_lib::DcApiInstructionDecoder>],
materializers: &[std::sync::Arc<dyn ks_lib::MtApiEventMaterializer>],
observer: &O,
) -> ks_core::Result<DevnetSplAssociatedTokenAccountExecutionSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
+ ks_store::DecodePipelineStore
+ Sync,
O: crate::SolanaExecutionObserver,
{
let prepared = match prepare_execution(http_pool, profile, wallet, request, observer).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
if !request.submit {
return std::result::Result::Ok(prepared.summary);
}
@@ -191,7 +230,7 @@ where
}
let signed = match prepared
.unsigned
.sign_after_simulation(&prepared.evidence, &[prepared.wallet.as_signer()])
.sign_after_simulation(&prepared.evidence, &[wallet.as_signer()])
{
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
@@ -460,7 +499,7 @@ where
async fn prepare_execution<O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
profile: &ks_config::ProfileConfig,
workspace_root: &std::path::Path,
wallet: &crate::DevnetExecutionWallet,
request: &DevnetSplAssociatedTokenAccountExecutionRequest,
observer: &O,
) -> ks_core::Result<PreparedAtaExecution>
@@ -491,11 +530,7 @@ where
),
));
}
let wallet = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet_summary = wallet.summary();
let wallet_summary = wallet.identity();
let fee_payer = ks_lib::MdPubkey(wallet_summary.public_key.clone());
let balance = match http_pool
.get_balance_for_role(
@@ -664,7 +699,7 @@ where
materializations: std::vec::Vec::new(),
post_execution: std::option::Option::None,
};
return std::result::Result::Ok(PreparedAtaExecution { wallet, unsigned, evidence, summary });
return std::result::Result::Ok(PreparedAtaExecution { unsigned, evidence, summary });
}
fn validate_profile(
@@ -676,9 +711,11 @@ fn validate_profile(
"SPL Associated Token Account Devnet orchestration requires a Devnet wallet profile",
));
}
if !profile.wallet.temporary_wallet_enabled || !profile.wallet.temporary_wallet_persist {
if profile.wallet.wallet_alias.is_none()
&& (!profile.wallet.temporary_wallet_enabled || !profile.wallet.temporary_wallet_persist)
{
return std::result::Result::Err(ks_core::Error::config(
"SPL Associated Token Account Devnet orchestration requires an enabled persistent temporary wallet",
"SPL Associated Token Account Devnet orchestration requires an enabled persistent temporary wallet when no native wallet alias is selected",
));
}
if !profile.execution.require_simulation {

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/spl/memo.rs
// version: 12
// version: 13
//! Devnet SPL Memo v4 execution with canonical post-validation.
@@ -124,6 +124,43 @@ pub async fn execute_devnet_memo<S, O>(
materializers: &[std::sync::Arc<dyn ks_lib::MtApiEventMaterializer>],
observer: &O,
) -> ks_core::Result<crate::DevnetMemoExecutionSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
+ ks_store::DecodePipelineStore
+ Sync,
O: crate::SolanaExecutionObserver,
{
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return execute_devnet_memo_with_wallet(
http_pool,
store,
profile,
&wallet,
request,
decoders,
materializers,
observer,
)
.await;
}
/// Executes one Devnet Memo operation with an explicitly resolved wallet capability.
#[allow(clippy::too_many_arguments)]
pub async fn execute_devnet_memo_with_wallet<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
request: &crate::DevnetMemoExecutionRequest,
decoders: &[std::sync::Arc<dyn ks_lib::DcApiInstructionDecoder>],
materializers: &[std::sync::Arc<dyn ks_lib::MtApiEventMaterializer>],
observer: &O,
) -> ks_core::Result<crate::DevnetMemoExecutionSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
@@ -155,11 +192,7 @@ where
),
));
}
let wallet = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet_summary = wallet.summary();
let wallet_summary = wallet.identity();
let fee_payer = ks_lib::MdPubkey(wallet_summary.public_key.clone());
let balance = match http_pool
.get_balance_for_role(
@@ -534,9 +567,11 @@ fn validate_profile(
"Memo Devnet orchestration requires a Devnet wallet profile",
));
}
if !profile.wallet.temporary_wallet_enabled || !profile.wallet.temporary_wallet_persist {
if profile.wallet.wallet_alias.is_none()
&& (!profile.wallet.temporary_wallet_enabled || !profile.wallet.temporary_wallet_persist)
{
return std::result::Result::Err(ks_core::Error::config(
"Memo Devnet orchestration requires an enabled persistent temporary wallet",
"Memo Devnet orchestration requires an enabled persistent temporary wallet when no native wallet alias is selected",
));
}
if !profile.execution.require_simulation {
@@ -825,7 +860,7 @@ mod tests {
profile.database.backend = "postgres".to_string();
profile.database.postgres.url = database_url;
if let std::result::Result::Ok(directory) = std::env::var("KS_DEVNET_WALLET_DIR") {
profile.wallet.wallet_dir = directory;
profile.wallet.temporary_wallet_dir = directory;
}
let pool = match ks_onchain_transport::HttpEndpointPool::from_profile(&profile) {
std::result::Result::Ok(value) => value,

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/spl/token/execution.rs
// version: 16
// version: 17
//! Devnet classic SPL Token execution with stateful and canonical post-validation.
@@ -105,7 +105,6 @@ pub struct DevnetSplTokenExecutionSummary {
}
struct PreparedTokenExecution {
wallet: ks_wallet::TemporaryWallet,
unsigned: ks_lib::ExSolanaUnsignedTransaction,
evidence: ks_lib::ExSolanaSimulationEvidence,
summary: crate::DevnetSplTokenExecutionSummary,
@@ -127,11 +126,15 @@ where
"simulate_devnet_spl_token requires submit=false",
));
}
let prepared =
match prepare_execution(http_pool, profile, workspace_root, request, observer).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
let prepared = match prepare_execution(http_pool, profile, &wallet, request, observer).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
return std::result::Result::Ok(prepared.summary);
}
@@ -154,11 +157,47 @@ where
+ Sync,
O: crate::SolanaExecutionObserver,
{
let prepared =
match prepare_execution(http_pool, profile, workspace_root, request, observer).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return execute_devnet_spl_token_with_wallet(
http_pool,
store,
profile,
&wallet,
request,
decoders,
materializers,
observer,
)
.await;
}
/// Executes this Devnet operation with an explicitly resolved wallet capability.
#[allow(clippy::too_many_arguments)]
pub async fn execute_devnet_spl_token_with_wallet<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
request: &crate::DevnetSplTokenExecutionRequest,
decoders: &[std::sync::Arc<dyn ks_lib::DcApiInstructionDecoder>],
materializers: &[std::sync::Arc<dyn ks_lib::MtApiEventMaterializer>],
observer: &O,
) -> ks_core::Result<crate::DevnetSplTokenExecutionSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
+ ks_store::DecodePipelineStore
+ Sync,
O: crate::SolanaExecutionObserver,
{
let prepared = match prepare_execution(http_pool, profile, wallet, request, observer).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
if !request.submit {
return std::result::Result::Ok(prepared.summary);
}
@@ -188,7 +227,7 @@ where
}
let signed = match prepared
.unsigned
.sign_after_simulation(&prepared.evidence, &[prepared.wallet.as_signer()])
.sign_after_simulation(&prepared.evidence, &[wallet.as_signer()])
{
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
@@ -428,7 +467,7 @@ where
async fn prepare_execution<O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
profile: &ks_config::ProfileConfig,
workspace_root: &std::path::Path,
wallet: &crate::DevnetExecutionWallet,
request: &crate::DevnetSplTokenExecutionRequest,
observer: &O,
) -> ks_core::Result<PreparedTokenExecution>
@@ -479,11 +518,7 @@ where
failed_readiness_message(&readiness),
));
}
let wallet = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet_summary = wallet.summary();
let wallet_summary = wallet.identity();
let fee_payer = ks_lib::MdPubkey(wallet_summary.public_key.clone());
let balance = match http_pool
.get_balance_for_role(
@@ -620,7 +655,7 @@ where
materializations: std::vec::Vec::new(),
post_execution: std::option::Option::None,
};
return std::result::Result::Ok(PreparedTokenExecution { wallet, unsigned, evidence, summary });
return std::result::Result::Ok(PreparedTokenExecution { unsigned, evidence, summary });
}
fn validate_profile(
@@ -632,9 +667,11 @@ fn validate_profile(
"SPL Token Devnet orchestration requires a Devnet wallet profile",
));
}
if !profile.wallet.temporary_wallet_enabled || !profile.wallet.temporary_wallet_persist {
if profile.wallet.wallet_alias.is_none()
&& (!profile.wallet.temporary_wallet_enabled || !profile.wallet.temporary_wallet_persist)
{
return std::result::Result::Err(ks_core::Error::config(
"SPL Token Devnet orchestration requires an enabled persistent temporary wallet",
"SPL Token Devnet orchestration requires an enabled persistent temporary wallet when no native wallet alias is selected",
));
}
if !profile.execution.require_simulation {
@@ -1093,7 +1130,7 @@ mod tests {
};
let mut profile = example_devnet_profile();
if let std::result::Result::Ok(directory) = std::env::var("KS_DEVNET_WALLET_DIR") {
profile.wallet.wallet_dir = directory;
profile.wallet.temporary_wallet_dir = directory;
}
let pool = match ks_onchain_transport::HttpEndpointPool::from_profile(&profile) {
std::result::Result::Ok(value) => value,
@@ -1263,7 +1300,7 @@ mod tests {
};
let mut profile = example_devnet_profile();
if let std::result::Result::Ok(directory) = std::env::var("KS_DEVNET_WALLET_DIR") {
profile.wallet.wallet_dir = directory;
profile.wallet.temporary_wallet_dir = directory;
}
let pool = match ks_onchain_transport::HttpEndpointPool::from_profile(&profile) {
std::result::Result::Ok(value) => value,

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/spl/token/lifecycle.rs
// version: 15
// version: 16
//! Controlled Devnet lifecycle for freshly prepared classic SPL Token accounts.
@@ -1512,7 +1512,7 @@ mod tests {
}
let mut profile = example_devnet_profile();
if let std::result::Result::Ok(directory) = std::env::var("KS_DEVNET_WALLET_DIR") {
profile.wallet.wallet_dir = directory;
profile.wallet.temporary_wallet_dir = directory;
}
let database_url = match std::env::var("KS_SECRET_POSTGRES_TEST_URL") {
std::result::Result::Ok(value) => value,

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/spl/token_2022/devnet_execution.rs
// version: 10
// version: 12
//! Devnet Token-2022 execution with stateful and canonical post-validation.
@@ -105,7 +105,6 @@ pub struct DevnetSplToken2022ExecutionSummary {
}
struct PreparedToken2022Execution {
wallet: ks_wallet::TemporaryWallet,
unsigned: ks_lib::ExSolanaUnsignedTransaction,
evidence: ks_lib::ExSolanaSimulationEvidence,
summary: crate::DevnetSplToken2022ExecutionSummary,
@@ -127,11 +126,15 @@ where
"simulate_devnet_spl_token_2022 requires submit=false",
));
}
let prepared =
match prepare_execution(http_pool, profile, workspace_root, request, observer).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
let prepared = match prepare_execution(http_pool, profile, &wallet, request, observer).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
return std::result::Result::Ok(prepared.summary);
}
@@ -154,11 +157,47 @@ where
+ Sync,
O: crate::SolanaExecutionObserver,
{
let prepared =
match prepare_execution(http_pool, profile, workspace_root, request, observer).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return execute_devnet_spl_token_2022_with_wallet(
http_pool,
store,
profile,
&wallet,
request,
decoders,
materializers,
observer,
)
.await;
}
/// Executes this Devnet operation with an explicitly resolved wallet capability.
#[allow(clippy::too_many_arguments)]
pub async fn execute_devnet_spl_token_2022_with_wallet<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
request: &crate::DevnetSplToken2022ExecutionRequest,
decoders: &[std::sync::Arc<dyn ks_lib::DcApiInstructionDecoder>],
materializers: &[std::sync::Arc<dyn ks_lib::MtApiEventMaterializer>],
observer: &O,
) -> ks_core::Result<crate::DevnetSplToken2022ExecutionSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
+ ks_store::DecodePipelineStore
+ Sync,
O: crate::SolanaExecutionObserver,
{
let prepared = match prepare_execution(http_pool, profile, wallet, request, observer).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
if !request.submit {
return std::result::Result::Ok(prepared.summary);
}
@@ -188,7 +227,7 @@ where
}
let signed = match prepared
.unsigned
.sign_after_simulation(&prepared.evidence, &[prepared.wallet.as_signer()])
.sign_after_simulation(&prepared.evidence, &[wallet.as_signer()])
{
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
@@ -428,7 +467,7 @@ where
async fn prepare_execution<O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
profile: &ks_config::ProfileConfig,
workspace_root: &std::path::Path,
wallet: &crate::DevnetExecutionWallet,
request: &crate::DevnetSplToken2022ExecutionRequest,
observer: &O,
) -> ks_core::Result<PreparedToken2022Execution>
@@ -469,11 +508,7 @@ where
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet_summary = wallet.summary();
let wallet_summary = wallet.identity();
let fee_payer = ks_lib::MdPubkey(wallet_summary.public_key.clone());
let balance = match http_pool
.get_balance_for_role(
@@ -610,12 +645,7 @@ where
materializations: std::vec::Vec::new(),
post_execution: std::option::Option::None,
};
return std::result::Result::Ok(PreparedToken2022Execution {
wallet,
unsigned,
evidence,
summary,
});
return std::result::Result::Ok(PreparedToken2022Execution { unsigned, evidence, summary });
}
fn preflight_request(
@@ -872,9 +902,11 @@ fn validate_profile(
"Token-2022 Devnet orchestration requires a Devnet wallet profile",
));
}
if !profile.wallet.temporary_wallet_enabled || !profile.wallet.temporary_wallet_persist {
if profile.wallet.wallet_alias.is_none()
&& (!profile.wallet.temporary_wallet_enabled || !profile.wallet.temporary_wallet_persist)
{
return std::result::Result::Err(ks_core::Error::config(
"Token-2022 Devnet orchestration requires an enabled persistent temporary wallet",
"Token-2022 Devnet orchestration requires an enabled persistent temporary wallet when no native wallet alias is selected",
));
}
if !profile.execution.require_simulation {

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/spl/token_2022/metadata/campaign.rs
// version: 9
// version: 10
//! Ordered confirmed Devnet campaign for the five Token-2022 Token Metadata instructions.
@@ -50,6 +50,34 @@ pub async fn execute_devnet_token_2022_metadata_campaign<S, O>(
options: &crate::Token2022MetadataFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetToken2022MetadataCampaignSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
+ ks_store::DecodePipelineStore
+ Sync,
O: crate::SolanaExecutionObserver,
{
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return execute_devnet_token_2022_metadata_campaign_with_wallet(
http_pool, store, profile, &wallet, options, observer,
)
.await;
}
/// Executes the Token-2022 metadata campaign with an explicitly resolved wallet.
#[allow(clippy::too_many_arguments)]
pub async fn execute_devnet_token_2022_metadata_campaign_with_wallet<S, O>(
http_pool: &ks_onchain_transport::HttpEndpointPool,
store: &S,
profile: &ks_config::ProfileConfig,
wallet: &crate::DevnetExecutionWallet,
options: &crate::Token2022MetadataFixturePreparationOptions,
observer: &O,
) -> ks_core::Result<crate::DevnetToken2022MetadataCampaignSummary>
where
S: ks_store::RawTransactionStore
+ ks_store::CoreExtractionStore
@@ -62,11 +90,8 @@ where
"Token-2022 Token Metadata Devnet campaign requires explicit operator confirmation",
));
}
let fixture = match crate::prepare_token_2022_metadata_fixture(
http_pool,
profile,
workspace_root,
options,
let fixture = match crate::prepare_token_2022_metadata_fixture_with_wallet(
http_pool, profile, wallet, options,
)
.await
{
@@ -90,11 +115,11 @@ where
request.submit = true;
request.operator_confirmed = true;
request.post_validation_max_retries = 20;
let execution = match crate::execute_devnet_spl_token_2022(
let execution = match crate::execute_devnet_spl_token_2022_with_wallet(
http_pool,
store,
profile,
workspace_root,
wallet,
&request,
decoders.as_slice(),
materializers.as_slice(),
@@ -521,7 +546,8 @@ mod tests {
if let std::result::Result::Err(error) = store.initialize_store_schema().await {
panic!("PostgreSQL schema initialization failed: {error}");
}
let configured_wallet_dir = std::path::PathBuf::from(profile.wallet.wallet_dir.as_str());
let configured_wallet_dir =
std::path::PathBuf::from(profile.wallet.temporary_wallet_dir.as_str());
let wallet_dir = if configured_wallet_dir.is_absolute() {
configured_wallet_dir
} else {

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/spl/token_2022/metadata/fixture.rs
// version: 6
// version: 7
//! Native Token-2022 mint preparation for the embedded Token Metadata Devnet campaign.
@@ -77,6 +77,22 @@ pub async fn prepare_token_2022_metadata_fixture(
profile: &ks_config::ProfileConfig,
workspace_root: &std::path::Path,
options: &crate::Token2022MetadataFixturePreparationOptions,
) -> ks_core::Result<crate::Token2022MetadataFixturePreparationSummary> {
let temporary = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let wallet = crate::DevnetExecutionWallet::Temporary(temporary);
return prepare_token_2022_metadata_fixture_with_wallet(http_pool, profile, &wallet, options)
.await;
}
/// Creates a fresh Token-2022 metadata fixture with an explicitly resolved execution wallet.
pub async fn prepare_token_2022_metadata_fixture_with_wallet(
http_pool: &ks_onchain_transport::HttpEndpointPool,
profile: &ks_config::ProfileConfig,
operator: &crate::DevnetExecutionWallet,
options: &crate::Token2022MetadataFixturePreparationOptions,
) -> ks_core::Result<crate::Token2022MetadataFixturePreparationSummary> {
if options.query_role.trim().is_empty() || options.transaction_role.trim().is_empty() {
return std::result::Result::Err(ks_core::Error::config(
@@ -84,8 +100,9 @@ pub async fn prepare_token_2022_metadata_fixture(
));
}
if profile.wallet.cluster != "devnet"
|| !profile.wallet.temporary_wallet_enabled
|| !profile.wallet.temporary_wallet_persist
|| (profile.wallet.wallet_alias.is_none()
&& (!profile.wallet.temporary_wallet_enabled
|| !profile.wallet.temporary_wallet_persist))
{
return std::result::Result::Err(ks_core::Error::config(
"Token-2022 metadata fixture requires a persistent Devnet wallet profile",
@@ -96,10 +113,6 @@ pub async fn prepare_token_2022_metadata_fixture(
"Token-2022 metadata fixture requires enabled Devnet submission and explicit operator confirmation",
));
}
let operator = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let fixture_store = match ks_wallet::TemporaryWalletStore::new(
options.wallet_dir.join("token_2022_metadata_validation"),
) {
@@ -147,7 +160,7 @@ pub async fn prepare_token_2022_metadata_fixture(
http_pool,
profile,
options,
&operator,
operator,
&mint_wallet,
mint_space,
rent_budget_space,
@@ -285,7 +298,7 @@ async fn create_native_token_2022_metadata_mint(
http_pool: &ks_onchain_transport::HttpEndpointPool,
profile: &ks_config::ProfileConfig,
options: &crate::Token2022MetadataFixturePreparationOptions,
operator: &ks_wallet::TemporaryWallet,
operator: &crate::DevnetExecutionWallet,
mint_wallet: &ks_wallet::TemporaryWallet,
mint_space: usize,
rent_budget_space: usize,

View File

@@ -0,0 +1,138 @@
// file: ks-pipeline-demo-scenarios/src/wallet.rs
// version: 1
//! Runtime wallet resolution shared by Devnet demonstration scenarios.
/// Resolved signing capability used by Devnet demonstration scenarios.
///
/// The enum owns either the historical managed temporary wallet or an
/// authenticated native `.kswallet`. It never exposes private key bytes.
pub enum DevnetExecutionWallet {
/// Managed temporary wallet used when no persistent alias is selected.
Temporary(ks_wallet::TemporaryWallet),
/// Authenticated native wallet selected explicitly by alias.
Persistent(ks_wallet::UnlockedWallet),
}
impl std::fmt::Debug for crate::DevnetExecutionWallet {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
return formatter
.debug_struct("DevnetExecutionWallet")
.field("identity", &self.identity())
.finish();
}
}
impl crate::DevnetExecutionWallet {
/// Returns the non-secret resolved wallet identity.
pub fn identity(&self) -> ks_wallet::WalletIdentity {
return match self {
Self::Temporary(wallet) => wallet.identity(),
Self::Persistent(wallet) => wallet.identity(),
};
}
/// Returns the resolved Solana public key.
pub fn public_key(&self) -> std::string::String {
return match self {
Self::Temporary(wallet) => wallet.public_key(),
Self::Persistent(wallet) => wallet.public_key(),
};
}
/// Returns whether this execution capability is temporary or native persistent.
pub fn persistence(&self) -> ks_wallet::WalletPersistence {
return match self {
Self::Temporary(wallet) => wallet.persistence(),
Self::Persistent(_) => ks_wallet::WalletPersistence::Persistent,
};
}
/// Returns the signer interface without exposing private key bytes.
pub fn as_signer(&self) -> &dyn solana_signer::Signer {
return match self {
Self::Temporary(wallet) => wallet.as_signer(),
Self::Persistent(wallet) => wallet.as_signer(),
};
}
/// Returns the signer interface while preserving `Sync` for async execution paths.
pub fn as_sync_signer(&self) -> &(dyn solana_signer::Signer + std::marker::Sync) {
return match self {
Self::Temporary(wallet) => wallet.as_sync_signer(),
Self::Persistent(wallet) => wallet.as_sync_signer(),
};
}
}
/// Resolves the execution wallet selected by one profile.
///
/// A profile with `wallet_alias` requires an explicit runtime password and
/// resolves only the native wallet store. A profile without `wallet_alias`
/// retains the managed temporary-wallet behavior.
pub async fn resolve_devnet_execution_wallet(
profile: &ks_config::ProfileConfig,
workspace_root: &std::path::Path,
password: std::option::Option<ks_wallet::WalletPassword>,
) -> ks_core::Result<crate::DevnetExecutionWallet> {
if profile.wallet.cluster != "devnet" {
return std::result::Result::Err(ks_core::Error::config(
"Devnet execution wallet resolution requires a Devnet profile",
));
}
if profile.wallet.wallet_alias.is_some() {
let password = match password {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(ks_core::Error::new(
"wallet_persistent_password_required",
"selected native wallet requires an explicit runtime password",
));
},
};
let wallet =
match crate::unlock_selected_profile_wallet(profile, workspace_root, password).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
tracing::info!(
target: "ks-pipeline-demo-scenarios.wallet",
action = "resolve_execution_wallet",
profile = profile.name.as_str(),
wallet_alias = wallet.alias().as_str(),
public_key = %wallet.public_key(),
persistence = "persistent",
"resolved authenticated native wallet for Devnet execution"
);
return std::result::Result::Ok(crate::DevnetExecutionWallet::Persistent(wallet));
}
let wallet = match crate::load_profile_temporary_wallet(profile, workspace_root).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
tracing::debug!(
target: "ks-pipeline-demo-scenarios.wallet",
action = "resolve_execution_wallet",
profile = profile.name.as_str(),
wallet_alias = wallet.identity().alias.as_str(),
public_key = %wallet.public_key(),
persistence = "temporary",
"resolved managed temporary wallet for Devnet execution"
);
return std::result::Result::Ok(crate::DevnetExecutionWallet::Temporary(wallet));
}
#[cfg(test)]
mod tests {
#[test]
fn debug_contains_only_non_secret_identity() {
let alias = ks_wallet::WalletAlias::parse("scenario-temp")
.unwrap_or_else(|error| panic!("alias must be valid: {error}"));
let wallet =
crate::DevnetExecutionWallet::Temporary(ks_wallet::TemporaryWallet::generate(alias));
let debug = format!("{wallet:?}");
assert!(debug.contains("scenario-temp"));
assert!(!debug.contains("keypair"));
assert!(!debug.contains("password"));
}
}