v0.4.7-pre.015

This commit is contained in:
2026-08-04 21:32:09 +02:00
parent b358b12f3b
commit 40d831f84d
7 changed files with 117 additions and 27 deletions

View File

@@ -1,5 +1,5 @@
# file: Cargo.toml
# version: 21
# version: 22
[workspace]
resolver = "3"
@@ -18,7 +18,7 @@ members = [
]
[workspace.package]
version = "0.4.7-pre.14"
version = "0.4.7-pre.15"
edition = "2024"
license = "MIT"
repository = "https://git.sasedev.com/Sasedev/khadhroony-bot3"

View File

@@ -0,0 +1,34 @@
<!-- file: docs/validation/V0_4_7_PRE_015_METAPLEX_NFT_LIFECYCLE.md -->
<!-- version: 1 -->
# Validation `0.4.7-pre.015` — cycle NFT classique
## Portée
Cette prérelease prolonge le parcours Devnet NFT classique validé en `pre.014`.
Le parcours exécutable devient :
1. création native du mint SPL classique ;
2. `Create` Metaplex avec metadata et master edition ;
3. `UpdateAsUpdateAuthorityV2` pour enregistrer la vente primaire ;
4. `UpdateAsUpdateAuthorityV2` avec `is_mutable = false`.
La master edition nest pas une étape séparée : elle est créée par le wrapper `Create` lorsque `master_edition` et `print_supply = Zero` sont fournis.
## Validation attendue
Pour chaque étape :
- préparation contextuelle ;
- simulation exacte réussie ;
- soumission explicitement confirmée ;
- confirmation Devnet ;
- relecture du PDA metadata ;
- matérialisation optionnelle du snapshot confirmé.
Après la dernière étape, une nouvelle mise à jour doit être refusée par Metaplex puisque les metadata sont immutables.
## Hors portée de cette prérelease
`Print` et `Burn` exigent encore des fixtures supplémentaires : token account du master, mint et token account de lédition, edition marker et comptes de burn. Ils restent à implémenter dans la prérelease suivante et ne sont pas déclarés validés ici.

View File

@@ -1,8 +1,13 @@
<!-- file: kb-app-demo-desktop/CHANGELOG.md -->
<!-- version: 22 -->
<!-- version: 23 -->
# CHANGELOG — kb-app-demo-desktop
## 0.4.7-pre.15
- expose létape NFT « rendre les metadata immutables » dans le runner cohérent ;
- prépare cette étape depuis le contexte confirmé de létape précédente ;
- maintient les lectures de postcondition et la matérialisation sur le PDA metadata.
## 0.4.7-pre.014
- Afficher les cinq parcours Metaplex Devnet dans le runner Metadata.

View File

@@ -1,5 +1,5 @@
// file: kb-app-demo-desktop/src/demo_execution_metadata.rs
// version: 13
// version: 14
//! Thin desktop adapters for metadata execution demo scenarios.
@@ -475,7 +475,8 @@ pub(crate) async fn demo_execution_metadata_prepare_step(
std::option::Option::Some(value) if !value.trim().is_empty() => value,
_ => {
return std::result::Result::Err(
"prepare and submit the Create step before preparing Update".to_string(),
"prepare and submit the previous NFT lifecycle step before continuing"
.to_string(),
);
},
};
@@ -494,7 +495,7 @@ pub(crate) async fn demo_execution_metadata_prepare_step(
return match previous_value.get(name).and_then(serde_json::Value::as_str) {
std::option::Option::Some(value) => std::result::Result::Ok(value.to_string()),
std::option::Option::None => std::result::Result::Err(format!(
"previous Create step does not contain `{name}`"
"previous scenario step does not contain `{name}`"
)),
};
};
@@ -506,14 +507,18 @@ pub(crate) async fn demo_execution_metadata_prepare_step(
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let master_edition = match string_field("master_edition") {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let authority = match string_field("authority") {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let master_edition =
match previous_value.get("master_edition").and_then(serde_json::Value::as_str) {
std::option::Option::Some(value) => value.to_string(),
std::option::Option::None => std::string::String::new(),
};
let immutable_transition = scenario.asset_family
== kb_pipeline_demo_scenarios::MetaplexTokenMetadataAssetFamily::Nft
&& step_index == 2;
let value = serde_json::json!({
"operation": "update_as_update_authority_v2",
"authority": authority.clone(),
@@ -527,8 +532,16 @@ pub(crate) async fn demo_execution_metadata_prepare_step(
"AsUpdateAuthorityV2": {
"new_update_authority": null,
"data": null,
"primary_sale_happened": true,
"is_mutable": null,
"primary_sale_happened": if immutable_transition {
serde_json::Value::Null
} else {
serde_json::json!(true)
},
"is_mutable": if immutable_transition {
serde_json::json!(false)
} else {
serde_json::Value::Null
},
"collection": "None",
"collection_details": "None",
"uses": "None",
@@ -543,7 +556,11 @@ pub(crate) async fn demo_execution_metadata_prepare_step(
metadata,
master_edition,
crate::pretty_json(&value),
"metadata_created".to_string(),
if immutable_transition {
"metadata_immutable".to_string()
} else {
"metadata_created".to_string()
},
)
};
let metadata_read = serde_json::json!({
@@ -580,7 +597,14 @@ pub(crate) async fn demo_execution_metadata_prepare_step(
scenario_id: scenario.id,
step_index,
operation: operation.clone(),
label: format!("Étape {} — {}", step_index + 1, operation),
label: if scenario.asset_family
== kb_pipeline_demo_scenarios::MetaplexTokenMetadataAssetFamily::Nft
&& step_index == 2
{
"Étape 3 — rendre les metadata immutables".to_string()
} else {
format!("Étape {}{}", step_index + 1, operation)
},
operation_json,
preflight_reads_json: crate::pretty_json(&preflight_reads),
postcondition_reads_json: crate::pretty_json(&postcondition_reads),

View File

@@ -1,8 +1,13 @@
<!-- file: kb-pipeline-demo-scenarios/CHANGELOG.md -->
<!-- version: 25 -->
<!-- version: 26 -->
# CHANGELOG — kb-pipeline-demo-scenarios
## 0.4.7-pre.15
- étend le parcours NFT Devnet à une troisième étape `UpdateAsUpdateAuthorityV2` qui rend les metadata immutables ;
- distingue lédition maître créée par `Create` des futures fixtures dédition imprimée ;
- conserve `Print` et `Burn` comme étapes ultérieures tant que leurs comptes SPL et édition ne sont pas préparés de bout en bout.
## 0.4.7-pre.014
- Expose cinq parcours Metaplex Devnet préparables : NFT, SFT, fungible, collection parent et pNFT sans rule set.

View File

@@ -27,3 +27,5 @@
## Report conditionnel — registre ElGamal
- [ ] Registre ElGamal - créer un scénario exécutable uniquement après confirmation du déploiement et disponibilité des preuves requises.
- Metaplex NFT Devnet — préparer les comptes SPL et PDA nécessaires aux étapes `Print` puis `Burn` après le parcours immuable de `pre.015`.

View File

@@ -1,5 +1,5 @@
// file: kb-pipeline-demo-scenarios/src/solana_metaplex_token_metadata_scenarios.rs
// version: 5
// version: 6
//! Coherent Metaplex Token Metadata scenario journeys for tests and Devnet campaigns.
@@ -47,6 +47,8 @@ pub enum MetaplexTokenMetadataFixtureState {
MetadataCreated,
/// Master edition exists.
MasterEditionCreated,
/// Metadata is immutable after a confirmed update-authority transition.
MetadataImmutable,
/// Collection member exists but is not verified.
CollectionMemberUnverified,
/// Collection member is verified.
@@ -226,8 +228,8 @@ pub fn metaplex_token_metadata_devnet_scenarios()
-> std::vec::Vec<crate::MetaplexTokenMetadataScenario> {
let definitions = [
(
"metaplex_nft_create_update_devnet",
"NFT classique : création confirmée puis mise à jour",
"metaplex_nft_lifecycle_devnet",
"NFT classique : création, mise à jour puis immutabilité",
crate::MetaplexTokenMetadataAssetFamily::Nft,
crate::MetaplexTokenMetadataFixtureKind::ClassicNftMint,
false,
@@ -289,11 +291,23 @@ pub fn metaplex_token_metadata_devnet_scenarios()
asset_family,
fixture_kind,
crate::MetaplexTokenMetadataFixtureState::MintPrepared,
crate::MetaplexTokenMetadataFixtureState::MetadataCreated,
vec![
kb_lib::EX_METAPLEX_TOKEN_METADATA_CREATE_OPERATION.to_string(),
kb_lib::EX_METAPLEX_TOKEN_METADATA_UPDATE_OPERATION.to_string(),
],
if asset_family == crate::MetaplexTokenMetadataAssetFamily::Nft {
crate::MetaplexTokenMetadataFixtureState::MetadataImmutable
} else {
crate::MetaplexTokenMetadataFixtureState::MetadataCreated
},
if asset_family == crate::MetaplexTokenMetadataAssetFamily::Nft {
vec![
kb_lib::EX_METAPLEX_TOKEN_METADATA_CREATE_OPERATION.to_string(),
kb_lib::EX_METAPLEX_TOKEN_METADATA_UPDATE_OPERATION.to_string(),
kb_lib::EX_METAPLEX_TOKEN_METADATA_UPDATE_OPERATION.to_string(),
]
} else {
vec![
kb_lib::EX_METAPLEX_TOKEN_METADATA_CREATE_OPERATION.to_string(),
kb_lib::EX_METAPLEX_TOKEN_METADATA_UPDATE_OPERATION.to_string(),
]
},
requires_collection,
requires_programmable_rules,
materialization_targets,
@@ -348,14 +362,20 @@ mod tests {
.collect::<std::collections::BTreeSet<_>>();
assert_eq!(families.len(), 5);
for scenario in devnet {
assert_eq!(scenario.operation_codes.len(), 2);
let expected_len =
if scenario.asset_family == crate::MetaplexTokenMetadataAssetFamily::Nft {
3
} else {
2
};
assert_eq!(scenario.operation_codes.len(), expected_len);
assert_eq!(
scenario.operation_codes[0],
kb_lib::EX_METAPLEX_TOKEN_METADATA_CREATE_OPERATION
);
assert_eq!(
scenario.operation_codes[1],
kb_lib::EX_METAPLEX_TOKEN_METADATA_UPDATE_OPERATION
assert!(
scenario.operation_codes[1..].iter().all(|operation| return operation
== kb_lib::EX_METAPLEX_TOKEN_METADATA_UPDATE_OPERATION)
);
assert_eq!(scenario.mode, crate::MetaplexTokenMetadataScenarioMode::NetworkSimulation);
}