v0.4.7-pre.015
This commit is contained in:
@@ -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"
|
||||
|
||||
34
docs/validation/V0_4_7_PRE_015_METAPLEX_NFT_LIFECYCLE.md
Normal file
34
docs/validation/V0_4_7_PRE_015_METAPLEX_NFT_LIFECYCLE.md
Normal 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 n’est 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.
|
||||
@@ -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.
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user