v0.4.7-pre.015
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
# file: Cargo.toml
|
# file: Cargo.toml
|
||||||
# version: 21
|
# version: 22
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
@@ -18,7 +18,7 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.4.7-pre.14"
|
version = "0.4.7-pre.15"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-bot3"
|
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 -->
|
<!-- file: kb-app-demo-desktop/CHANGELOG.md -->
|
||||||
<!-- version: 22 -->
|
<!-- version: 23 -->
|
||||||
|
|
||||||
# CHANGELOG — kb-app-demo-desktop
|
# 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
|
## 0.4.7-pre.014
|
||||||
|
|
||||||
- Afficher les cinq parcours Metaplex Devnet dans le runner Metadata.
|
- Afficher les cinq parcours Metaplex Devnet dans le runner Metadata.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: kb-app-demo-desktop/src/demo_execution_metadata.rs
|
// file: kb-app-demo-desktop/src/demo_execution_metadata.rs
|
||||||
// version: 13
|
// version: 14
|
||||||
|
|
||||||
//! Thin desktop adapters for metadata execution demo scenarios.
|
//! 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,
|
std::option::Option::Some(value) if !value.trim().is_empty() => value,
|
||||||
_ => {
|
_ => {
|
||||||
return std::result::Result::Err(
|
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) {
|
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::Some(value) => std::result::Result::Ok(value.to_string()),
|
||||||
std::option::Option::None => std::result::Result::Err(format!(
|
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::Ok(value) => value,
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
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") {
|
let authority = match string_field("authority") {
|
||||||
std::result::Result::Ok(value) => value,
|
std::result::Result::Ok(value) => value,
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
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!({
|
let value = serde_json::json!({
|
||||||
"operation": "update_as_update_authority_v2",
|
"operation": "update_as_update_authority_v2",
|
||||||
"authority": authority.clone(),
|
"authority": authority.clone(),
|
||||||
@@ -527,8 +532,16 @@ pub(crate) async fn demo_execution_metadata_prepare_step(
|
|||||||
"AsUpdateAuthorityV2": {
|
"AsUpdateAuthorityV2": {
|
||||||
"new_update_authority": null,
|
"new_update_authority": null,
|
||||||
"data": null,
|
"data": null,
|
||||||
"primary_sale_happened": true,
|
"primary_sale_happened": if immutable_transition {
|
||||||
"is_mutable": null,
|
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": "None",
|
||||||
"collection_details": "None",
|
"collection_details": "None",
|
||||||
"uses": "None",
|
"uses": "None",
|
||||||
@@ -543,7 +556,11 @@ pub(crate) async fn demo_execution_metadata_prepare_step(
|
|||||||
metadata,
|
metadata,
|
||||||
master_edition,
|
master_edition,
|
||||||
crate::pretty_json(&value),
|
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!({
|
let metadata_read = serde_json::json!({
|
||||||
@@ -580,7 +597,14 @@ pub(crate) async fn demo_execution_metadata_prepare_step(
|
|||||||
scenario_id: scenario.id,
|
scenario_id: scenario.id,
|
||||||
step_index,
|
step_index,
|
||||||
operation: operation.clone(),
|
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,
|
operation_json,
|
||||||
preflight_reads_json: crate::pretty_json(&preflight_reads),
|
preflight_reads_json: crate::pretty_json(&preflight_reads),
|
||||||
postcondition_reads_json: crate::pretty_json(&postcondition_reads),
|
postcondition_reads_json: crate::pretty_json(&postcondition_reads),
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
<!-- file: kb-pipeline-demo-scenarios/CHANGELOG.md -->
|
<!-- file: kb-pipeline-demo-scenarios/CHANGELOG.md -->
|
||||||
<!-- version: 25 -->
|
<!-- version: 26 -->
|
||||||
|
|
||||||
# CHANGELOG — kb-pipeline-demo-scenarios
|
# 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
|
## 0.4.7-pre.014
|
||||||
|
|
||||||
- Expose cinq parcours Metaplex Devnet préparables : NFT, SFT, fungible, collection parent et pNFT sans rule set.
|
- 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
|
## 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.
|
- [ ] 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
|
// 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.
|
//! Coherent Metaplex Token Metadata scenario journeys for tests and Devnet campaigns.
|
||||||
|
|
||||||
@@ -47,6 +47,8 @@ pub enum MetaplexTokenMetadataFixtureState {
|
|||||||
MetadataCreated,
|
MetadataCreated,
|
||||||
/// Master edition exists.
|
/// Master edition exists.
|
||||||
MasterEditionCreated,
|
MasterEditionCreated,
|
||||||
|
/// Metadata is immutable after a confirmed update-authority transition.
|
||||||
|
MetadataImmutable,
|
||||||
/// Collection member exists but is not verified.
|
/// Collection member exists but is not verified.
|
||||||
CollectionMemberUnverified,
|
CollectionMemberUnverified,
|
||||||
/// Collection member is verified.
|
/// Collection member is verified.
|
||||||
@@ -226,8 +228,8 @@ pub fn metaplex_token_metadata_devnet_scenarios()
|
|||||||
-> std::vec::Vec<crate::MetaplexTokenMetadataScenario> {
|
-> std::vec::Vec<crate::MetaplexTokenMetadataScenario> {
|
||||||
let definitions = [
|
let definitions = [
|
||||||
(
|
(
|
||||||
"metaplex_nft_create_update_devnet",
|
"metaplex_nft_lifecycle_devnet",
|
||||||
"NFT classique : création confirmée puis mise à jour",
|
"NFT classique : création, mise à jour puis immutabilité",
|
||||||
crate::MetaplexTokenMetadataAssetFamily::Nft,
|
crate::MetaplexTokenMetadataAssetFamily::Nft,
|
||||||
crate::MetaplexTokenMetadataFixtureKind::ClassicNftMint,
|
crate::MetaplexTokenMetadataFixtureKind::ClassicNftMint,
|
||||||
false,
|
false,
|
||||||
@@ -289,11 +291,23 @@ pub fn metaplex_token_metadata_devnet_scenarios()
|
|||||||
asset_family,
|
asset_family,
|
||||||
fixture_kind,
|
fixture_kind,
|
||||||
crate::MetaplexTokenMetadataFixtureState::MintPrepared,
|
crate::MetaplexTokenMetadataFixtureState::MintPrepared,
|
||||||
crate::MetaplexTokenMetadataFixtureState::MetadataCreated,
|
if asset_family == crate::MetaplexTokenMetadataAssetFamily::Nft {
|
||||||
vec![
|
crate::MetaplexTokenMetadataFixtureState::MetadataImmutable
|
||||||
kb_lib::EX_METAPLEX_TOKEN_METADATA_CREATE_OPERATION.to_string(),
|
} else {
|
||||||
kb_lib::EX_METAPLEX_TOKEN_METADATA_UPDATE_OPERATION.to_string(),
|
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_collection,
|
||||||
requires_programmable_rules,
|
requires_programmable_rules,
|
||||||
materialization_targets,
|
materialization_targets,
|
||||||
@@ -348,14 +362,20 @@ mod tests {
|
|||||||
.collect::<std::collections::BTreeSet<_>>();
|
.collect::<std::collections::BTreeSet<_>>();
|
||||||
assert_eq!(families.len(), 5);
|
assert_eq!(families.len(), 5);
|
||||||
for scenario in devnet {
|
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!(
|
assert_eq!(
|
||||||
scenario.operation_codes[0],
|
scenario.operation_codes[0],
|
||||||
kb_lib::EX_METAPLEX_TOKEN_METADATA_CREATE_OPERATION
|
kb_lib::EX_METAPLEX_TOKEN_METADATA_CREATE_OPERATION
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert!(
|
||||||
scenario.operation_codes[1],
|
scenario.operation_codes[1..].iter().all(|operation| return operation
|
||||||
kb_lib::EX_METAPLEX_TOKEN_METADATA_UPDATE_OPERATION
|
== kb_lib::EX_METAPLEX_TOKEN_METADATA_UPDATE_OPERATION)
|
||||||
);
|
);
|
||||||
assert_eq!(scenario.mode, crate::MetaplexTokenMetadataScenarioMode::NetworkSimulation);
|
assert_eq!(scenario.mode, crate::MetaplexTokenMetadataScenarioMode::NetworkSimulation);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user