v0.4.7-pre.005

This commit is contained in:
2026-08-02 11:02:05 +02:00
parent d3b63e3a3c
commit 80f102b129
13 changed files with 825 additions and 27 deletions

View File

@@ -1,8 +1,16 @@
<!-- file: kb-lib/CHANGELOG.md -->
<!-- version: 11 -->
<!-- version: 12 -->
# CHANGELOG — kb-lib
## 0.4.7-pre.005 — programmable NFTs et délégations
- ajout des wrappers officiels `Burn`, `Delegate`, `Revoke`, `Lock`, `Unlock`, `Transfer` et `CloseAccounts` ;
- validation du couplage des comptes Token Authorization Rules et maintien de la simulation obligatoire ;
- exposition des codes dopération, bindings TS-RS et capacités exactes correspondantes ;
- ajout de tests unitaires dans `intent.rs`, `builder.rs` et `executor.rs` ;
- maintien des versions remplacées en decode-only avec renvoi vers leur wrapper canonique.
## 0.4.7-pre.004 — collections, créateurs et autorités
- ajout des wrappers courants `Verify` et `Unverify` pour les créateurs et collections ;

View File

@@ -1,5 +1,5 @@
<!-- file: kb-lib/README.md -->
<!-- version: 16 -->
<!-- version: 17 -->
# kb-lib
@@ -58,7 +58,7 @@ Les matrices actives sont maintenues sous [`../test-fixtures/contract-matrices/`
## Statut et limites
La migration des surfaces historiques jusquà un périmètre proche de bot2 `0.4.6` est largement réalisée. Le décodeur Metaplex Token Metadata couvre les 58 discriminants et les matérialisations possèdent désormais un contrat fermé de propriété des faits. Lexécuteur Metaplex possède désormais ses fondations typées et les wrappers courants `Create`/`Update` et `Verify`/`Unverify`, ainsi que les opérations dépréciées `PuffMetadata`, `SetTokenStandard` et `SetCollectionSize`; les autres opérations courantes restent à achever jusquà `pre.006`. Le registre ElGamal nest pas déclaré validé sur Devnet ou Mainnet.
La migration des surfaces historiques jusquà un périmètre proche de bot2 `0.4.6` est largement réalisée. Le décodeur Metaplex Token Metadata couvre les 58 discriminants et les matérialisations possèdent désormais un contrat fermé de propriété des faits. Lexécuteur Metaplex possède désormais ses fondations typées et les wrappers courants `Create`/`Update`, `Verify`/`Unverify`, `Burn`, `Delegate`/`Revoke`, `Lock`/`Unlock`, `Transfer` et `CloseAccounts`, ainsi que les opérations dépréciées `PuffMetadata`, `SetTokenStandard` et `SetCollectionSize`; les éditions, uses, escrow et opérations restantes doivent être fermés en `pre.006`. Le registre ElGamal nest pas déclaré validé sur Devnet ou Mainnet.
## Documents

View File

@@ -1,5 +1,5 @@
<!-- file: kb-lib/TODO.md -->
<!-- version: 8 -->
<!-- version: 9 -->
# TODO — kb-lib
@@ -8,7 +8,8 @@
- [x] établir le contrat fermé de couverture et de propriété des faits ;
- [x] introduire les intents et builders courants `Create`/`Update` ;
- [x] achever les wrappers courants Verify/Unverify et lopération dépréciée SetCollectionSize ;
- [ ] achever délégations, pNFT, éditions, use, escrow et opérations courantes restantes avant `pre.006` ;
- [x] achever délégations et opérations pNFT `Burn`/`Lock`/`Unlock`/`Transfer`/`CloseAccounts` ;
- [ ] achever éditions, use, escrow et opérations courantes restantes en `pre.006` ;
## Entre `0.4.6` et `0.4.7` — Metaplex Token Metadata

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/executor.rs
// version: 12
// version: 13
//! Consolidated executor modules.
@@ -208,18 +208,32 @@ pub use self::lending::ExLendingKaminoExecutor;
pub use self::lending::ExLendingMarginfiV2Executor;
/// Exposes the reserved `lock/raydium_lp` executor.
pub use self::lock::ExLockRaydiumLpExecutor;
/// Stable operation code for Metaplex Burn.
pub use self::metadata::EX_METAPLEX_TOKEN_METADATA_BURN_OPERATION;
/// Stable operation code for Metaplex Close Accounts.
pub use self::metadata::EX_METAPLEX_TOKEN_METADATA_CLOSE_ACCOUNTS_OPERATION;
/// Stable operation code for the current Metaplex Create wrapper.
pub use self::metadata::EX_METAPLEX_TOKEN_METADATA_CREATE_OPERATION;
/// Stable operation code for Metaplex Delegate.
pub use self::metadata::EX_METAPLEX_TOKEN_METADATA_DELEGATE_OPERATION;
/// Deprecated Metaplex operation codes requiring explicit approval.
pub use self::metadata::EX_METAPLEX_TOKEN_METADATA_DEPRECATED_OPERATION_CODES;
/// Stable operation code for Metaplex Lock.
pub use self::metadata::EX_METAPLEX_TOKEN_METADATA_LOCK_OPERATION;
/// Stable deprecated Metaplex PuffMetadata operation code.
pub use self::metadata::EX_METAPLEX_TOKEN_METADATA_PUFF_METADATA_OPERATION;
/// Stable operation code for Metaplex Revoke.
pub use self::metadata::EX_METAPLEX_TOKEN_METADATA_REVOKE_OPERATION;
/// Stable deprecated Metaplex SetCollectionSize operation code.
pub use self::metadata::EX_METAPLEX_TOKEN_METADATA_SET_COLLECTION_SIZE_OPERATION;
/// Stable deprecated Metaplex SetTokenStandard operation code.
pub use self::metadata::EX_METAPLEX_TOKEN_METADATA_SET_TOKEN_STANDARD_OPERATION;
/// Current and deprecated Metaplex Token Metadata operations.
pub use self::metadata::EX_METAPLEX_TOKEN_METADATA_SUPPORTED_OPERATION_CODES;
/// Stable operation code for Metaplex Transfer.
pub use self::metadata::EX_METAPLEX_TOKEN_METADATA_TRANSFER_OPERATION;
/// Stable operation code for Metaplex Unlock.
pub use self::metadata::EX_METAPLEX_TOKEN_METADATA_UNLOCK_OPERATION;
/// Stable operation code for the current Metaplex Unverify wrapper.
pub use self::metadata::EX_METAPLEX_TOKEN_METADATA_UNVERIFY_OPERATION;
/// Stable operation code for the current Metaplex Update wrapper.

View File

@@ -1,18 +1,25 @@
// file: kb-lib/src/executor/metadata.rs
// version: 6
// version: 7
//! `metadata` executor family.
mod metaplex_token_metadata;
mod solana_program_metadata;
mod spl_name_service;
pub use self::metaplex_token_metadata::EX_METAPLEX_TOKEN_METADATA_BURN_OPERATION;
pub use self::metaplex_token_metadata::EX_METAPLEX_TOKEN_METADATA_CLOSE_ACCOUNTS_OPERATION;
/// Exposes the Metaplex Token Metadata execution surface.
pub use self::metaplex_token_metadata::EX_METAPLEX_TOKEN_METADATA_CREATE_OPERATION;
pub use self::metaplex_token_metadata::EX_METAPLEX_TOKEN_METADATA_DELEGATE_OPERATION;
pub use self::metaplex_token_metadata::EX_METAPLEX_TOKEN_METADATA_DEPRECATED_OPERATION_CODES;
pub use self::metaplex_token_metadata::EX_METAPLEX_TOKEN_METADATA_LOCK_OPERATION;
pub use self::metaplex_token_metadata::EX_METAPLEX_TOKEN_METADATA_PUFF_METADATA_OPERATION;
pub use self::metaplex_token_metadata::EX_METAPLEX_TOKEN_METADATA_REVOKE_OPERATION;
pub use self::metaplex_token_metadata::EX_METAPLEX_TOKEN_METADATA_SET_COLLECTION_SIZE_OPERATION;
pub use self::metaplex_token_metadata::EX_METAPLEX_TOKEN_METADATA_SET_TOKEN_STANDARD_OPERATION;
pub use self::metaplex_token_metadata::EX_METAPLEX_TOKEN_METADATA_SUPPORTED_OPERATION_CODES;
pub use self::metaplex_token_metadata::EX_METAPLEX_TOKEN_METADATA_TRANSFER_OPERATION;
pub use self::metaplex_token_metadata::EX_METAPLEX_TOKEN_METADATA_UNLOCK_OPERATION;
pub use self::metaplex_token_metadata::EX_METAPLEX_TOKEN_METADATA_UNVERIFY_OPERATION;
pub use self::metaplex_token_metadata::EX_METAPLEX_TOKEN_METADATA_UPDATE_OPERATION;
pub use self::metaplex_token_metadata::EX_METAPLEX_TOKEN_METADATA_VERIFY_OPERATION;

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/executor/metadata/metaplex_token_metadata.rs
// version: 8
// version: 9
//! Metaplex Token Metadata typed execution surface.
@@ -9,18 +9,32 @@ mod intent;
/// Exposes the Metaplex Token Metadata executor.
pub use self::executor::ExMetadataMetaplexTokenMetadataExecutor;
/// Stable operation code for Metaplex Burn.
pub use self::intent::EX_METAPLEX_TOKEN_METADATA_BURN_OPERATION;
/// Stable operation code for Metaplex Close Accounts.
pub use self::intent::EX_METAPLEX_TOKEN_METADATA_CLOSE_ACCOUNTS_OPERATION;
/// Stable operation code for the current Create wrapper.
pub use self::intent::EX_METAPLEX_TOKEN_METADATA_CREATE_OPERATION;
/// Stable operation code for Metaplex Delegate.
pub use self::intent::EX_METAPLEX_TOKEN_METADATA_DELEGATE_OPERATION;
/// Deprecated operation codes requiring explicit operator approval.
pub use self::intent::EX_METAPLEX_TOKEN_METADATA_DEPRECATED_OPERATION_CODES;
/// Stable operation code for Metaplex Lock.
pub use self::intent::EX_METAPLEX_TOKEN_METADATA_LOCK_OPERATION;
/// Stable deprecated operation code for PuffMetadata.
pub use self::intent::EX_METAPLEX_TOKEN_METADATA_PUFF_METADATA_OPERATION;
/// Stable operation code for Metaplex Revoke.
pub use self::intent::EX_METAPLEX_TOKEN_METADATA_REVOKE_OPERATION;
/// Stable deprecated operation code for SetCollectionSize.
pub use self::intent::EX_METAPLEX_TOKEN_METADATA_SET_COLLECTION_SIZE_OPERATION;
/// Stable deprecated operation code for SetTokenStandard.
pub use self::intent::EX_METAPLEX_TOKEN_METADATA_SET_TOKEN_STANDARD_OPERATION;
/// Current and deprecated operations implemented by this prerelease.
pub use self::intent::EX_METAPLEX_TOKEN_METADATA_SUPPORTED_OPERATION_CODES;
/// Stable operation code for Metaplex Transfer.
pub use self::intent::EX_METAPLEX_TOKEN_METADATA_TRANSFER_OPERATION;
/// Stable operation code for Metaplex Unlock.
pub use self::intent::EX_METAPLEX_TOKEN_METADATA_UNLOCK_OPERATION;
/// Stable operation code for the current Unverify wrapper.
pub use self::intent::EX_METAPLEX_TOKEN_METADATA_UNVERIFY_OPERATION;
/// Stable operation code for the current Update wrapper.

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/executor/metadata/metaplex_token_metadata/builder.rs
// version: 5
// version: 6
//! Official Metaplex builders and conservative plan validation.
@@ -19,6 +19,17 @@ macro_rules! parse_official_pubkey {
}};
}
macro_rules! parse_optional_official_pubkey {
($value:expr, $field:expr) => {{
match $value {
std::option::Option::Some(value) => {
std::option::Option::Some(parse_official_pubkey!(&value.0, $field))
},
std::option::Option::None => std::option::Option::None,
}
}};
}
macro_rules! convert_official_instruction {
($instruction:expr) => {{
let instruction = $instruction;
@@ -151,6 +162,178 @@ pub(crate) fn executor_metaplex_token_metadata_build_prepared_plan(
collection_authority_record.as_ref(),
*size,
),
crate::ExMetaplexTokenMetadataOperation::Burn {
authority,
collection_metadata,
metadata,
edition,
mint,
token,
master_edition,
master_edition_mint,
master_edition_token,
edition_marker,
token_record,
burn_args,
} => build_burn(
authority,
collection_metadata.as_ref(),
metadata,
edition.as_ref(),
mint,
token,
master_edition.as_ref(),
master_edition_mint.as_ref(),
master_edition_token.as_ref(),
edition_marker.as_ref(),
token_record.as_ref(),
burn_args,
),
crate::ExMetaplexTokenMetadataOperation::Delegate {
delegate_record,
delegate,
metadata,
master_edition,
token_record,
mint,
token,
authority,
spl_token_program,
authorization_rules_program,
authorization_rules,
delegate_args,
} => build_delegate(
intent,
delegate_record.as_ref(),
delegate,
metadata,
master_edition.as_ref(),
token_record.as_ref(),
mint,
token.as_ref(),
authority,
spl_token_program.as_ref(),
authorization_rules_program.as_ref(),
authorization_rules.as_ref(),
delegate_args,
),
crate::ExMetaplexTokenMetadataOperation::Revoke {
delegate_record,
delegate,
metadata,
master_edition,
token_record,
mint,
token,
authority,
spl_token_program,
authorization_rules_program,
authorization_rules,
revoke_args,
} => build_revoke(
intent,
delegate_record.as_ref(),
delegate,
metadata,
master_edition.as_ref(),
token_record.as_ref(),
mint,
token.as_ref(),
authority,
spl_token_program.as_ref(),
authorization_rules_program.as_ref(),
authorization_rules.as_ref(),
revoke_args,
),
crate::ExMetaplexTokenMetadataOperation::Lock {
authority,
token_owner,
token,
mint,
metadata,
edition,
token_record,
spl_token_program,
authorization_rules_program,
authorization_rules,
lock_args,
} => build_lock(
intent,
authority,
token_owner.as_ref(),
token,
mint,
metadata,
edition.as_ref(),
token_record.as_ref(),
spl_token_program.as_ref(),
authorization_rules_program.as_ref(),
authorization_rules.as_ref(),
lock_args,
),
crate::ExMetaplexTokenMetadataOperation::Unlock {
authority,
token_owner,
token,
mint,
metadata,
edition,
token_record,
spl_token_program,
authorization_rules_program,
authorization_rules,
unlock_args,
} => build_unlock(
intent,
authority,
token_owner.as_ref(),
token,
mint,
metadata,
edition.as_ref(),
token_record.as_ref(),
spl_token_program.as_ref(),
authorization_rules_program.as_ref(),
authorization_rules.as_ref(),
unlock_args,
),
crate::ExMetaplexTokenMetadataOperation::Transfer {
token,
token_owner,
destination_token,
destination_owner,
mint,
metadata,
edition,
token_record,
destination_token_record,
authority,
authorization_rules_program,
authorization_rules,
transfer_args,
} => build_transfer(
intent,
token,
token_owner,
destination_token,
destination_owner,
mint,
metadata,
edition.as_ref(),
token_record.as_ref(),
destination_token_record.as_ref(),
authority,
authorization_rules_program.as_ref(),
authorization_rules.as_ref(),
transfer_args,
),
crate::ExMetaplexTokenMetadataOperation::CloseAccounts {
metadata,
edition,
mint,
authority,
destination,
} => build_close_accounts(metadata, edition, mint, authority, destination),
};
let instruction = match instruction_result {
std::result::Result::Ok(value) => value,
@@ -197,7 +380,7 @@ fn validate_intent(intent: &crate::ExMetaplexTokenMetadataExecutionIntent) -> kb
if !intent.policy.dry_run {
return std::result::Result::Err(kb_core::Error::new(
"execution_metaplex_dry_run_required",
"Metaplex Token Metadata pre.004 intents are simulation-only",
"Metaplex Token Metadata pre.005 intents are simulation-only",
));
}
match intent.policy.cost_limit.max_fee_lamports {
@@ -787,6 +970,393 @@ fn required_signers(
return required;
}
fn validate_rule_accounts(
program: std::option::Option<&crate::MdProgramId>,
rules: std::option::Option<&crate::MdPubkey>,
) -> kb_core::Result<()> {
if program.is_some() != rules.is_some() {
return std::result::Result::Err(kb_core::Error::new(
"execution_metaplex_rule_set_accounts_incomplete",
"authorization rules program and account must be supplied together",
));
}
return std::result::Result::Ok(());
}
#[allow(clippy::too_many_arguments)]
fn build_delegate(
intent: &crate::ExMetaplexTokenMetadataExecutionIntent,
delegate_record: std::option::Option<&crate::MdPubkey>,
delegate: &crate::MdPubkey,
metadata: &crate::MdPubkey,
master_edition: std::option::Option<&crate::MdPubkey>,
token_record: std::option::Option<&crate::MdPubkey>,
mint: &crate::MdPubkey,
token: std::option::Option<&crate::MdPubkey>,
authority: &crate::MdPubkey,
spl_token_program: std::option::Option<&crate::MdProgramId>,
authorization_rules_program: std::option::Option<&crate::MdProgramId>,
authorization_rules: std::option::Option<&crate::MdPubkey>,
delegate_args: &mpl_token_metadata::types::DelegateArgs,
) -> kb_core::Result<solana_instruction::Instruction> {
if let std::result::Result::Err(error) =
validate_rule_accounts(authorization_rules_program, authorization_rules)
{
return std::result::Result::Err(error);
}
let official = mpl_token_metadata::instructions::Delegate {
delegate_record: parse_optional_official_pubkey!(delegate_record, "delegate_record"),
delegate: parse_official_pubkey!(&delegate.0, "delegate"),
metadata: parse_official_pubkey!(&metadata.0, "metadata"),
master_edition: parse_optional_official_pubkey!(master_edition, "master_edition"),
token_record: parse_optional_official_pubkey!(token_record, "token_record"),
mint: parse_official_pubkey!(&mint.0, "mint"),
token: parse_optional_official_pubkey!(token, "token"),
authority: parse_official_pubkey!(&authority.0, "authority"),
payer: parse_official_pubkey!(&intent.fee_payer.0, "fee_payer"),
system_program: parse_official_pubkey!(kb_program_ids::SYSTEM_PROGRAM_ID, "system_program"),
sysvar_instructions: parse_official_pubkey!(
kb_program_ids::SYSVAR_INSTRUCTIONS_PROGRAM_ID,
"sysvar_instructions"
),
spl_token_program: match spl_token_program {
std::option::Option::Some(v) => {
std::option::Option::Some(parse_official_pubkey!(&v.0, "spl_token_program"))
},
std::option::Option::None => std::option::Option::None,
},
authorization_rules_program: match authorization_rules_program {
std::option::Option::Some(v) => std::option::Option::Some(parse_official_pubkey!(
&v.0,
"authorization_rules_program"
)),
std::option::Option::None => std::option::Option::None,
},
authorization_rules: parse_optional_official_pubkey!(
authorization_rules,
"authorization_rules"
),
}
.instruction(mpl_token_metadata::instructions::DelegateInstructionArgs {
delegate_args: delegate_args.clone(),
});
return std::result::Result::Ok(convert_official_instruction!(official));
}
#[allow(clippy::too_many_arguments)]
fn build_revoke(
intent: &crate::ExMetaplexTokenMetadataExecutionIntent,
delegate_record: std::option::Option<&crate::MdPubkey>,
delegate: &crate::MdPubkey,
metadata: &crate::MdPubkey,
master_edition: std::option::Option<&crate::MdPubkey>,
token_record: std::option::Option<&crate::MdPubkey>,
mint: &crate::MdPubkey,
token: std::option::Option<&crate::MdPubkey>,
authority: &crate::MdPubkey,
spl_token_program: std::option::Option<&crate::MdProgramId>,
authorization_rules_program: std::option::Option<&crate::MdProgramId>,
authorization_rules: std::option::Option<&crate::MdPubkey>,
revoke_args: &mpl_token_metadata::types::RevokeArgs,
) -> kb_core::Result<solana_instruction::Instruction> {
if let std::result::Result::Err(error) =
validate_rule_accounts(authorization_rules_program, authorization_rules)
{
return std::result::Result::Err(error);
}
let official = mpl_token_metadata::instructions::Revoke {
delegate_record: parse_optional_official_pubkey!(delegate_record, "delegate_record"),
delegate: parse_official_pubkey!(&delegate.0, "delegate"),
metadata: parse_official_pubkey!(&metadata.0, "metadata"),
master_edition: parse_optional_official_pubkey!(master_edition, "master_edition"),
token_record: parse_optional_official_pubkey!(token_record, "token_record"),
mint: parse_official_pubkey!(&mint.0, "mint"),
token: parse_optional_official_pubkey!(token, "token"),
authority: parse_official_pubkey!(&authority.0, "authority"),
payer: parse_official_pubkey!(&intent.fee_payer.0, "fee_payer"),
system_program: parse_official_pubkey!(kb_program_ids::SYSTEM_PROGRAM_ID, "system_program"),
sysvar_instructions: parse_official_pubkey!(
kb_program_ids::SYSVAR_INSTRUCTIONS_PROGRAM_ID,
"sysvar_instructions"
),
spl_token_program: match spl_token_program {
std::option::Option::Some(v) => {
std::option::Option::Some(parse_official_pubkey!(&v.0, "spl_token_program"))
},
std::option::Option::None => std::option::Option::None,
},
authorization_rules_program: match authorization_rules_program {
std::option::Option::Some(v) => std::option::Option::Some(parse_official_pubkey!(
&v.0,
"authorization_rules_program"
)),
std::option::Option::None => std::option::Option::None,
},
authorization_rules: parse_optional_official_pubkey!(
authorization_rules,
"authorization_rules"
),
}
.instruction(mpl_token_metadata::instructions::RevokeInstructionArgs {
revoke_args: revoke_args.clone(),
});
return std::result::Result::Ok(convert_official_instruction!(official));
}
#[allow(clippy::too_many_arguments)]
fn build_lock(
intent: &crate::ExMetaplexTokenMetadataExecutionIntent,
authority: &crate::MdPubkey,
token_owner: std::option::Option<&crate::MdPubkey>,
token: &crate::MdPubkey,
mint: &crate::MdPubkey,
metadata: &crate::MdPubkey,
edition: std::option::Option<&crate::MdPubkey>,
token_record: std::option::Option<&crate::MdPubkey>,
spl_token_program: std::option::Option<&crate::MdProgramId>,
authorization_rules_program: std::option::Option<&crate::MdProgramId>,
authorization_rules: std::option::Option<&crate::MdPubkey>,
lock_args: &mpl_token_metadata::types::LockArgs,
) -> kb_core::Result<solana_instruction::Instruction> {
if let std::result::Result::Err(error) =
validate_rule_accounts(authorization_rules_program, authorization_rules)
{
return std::result::Result::Err(error);
}
let official = mpl_token_metadata::instructions::Lock {
authority: parse_official_pubkey!(&authority.0, "authority"),
token_owner: parse_optional_official_pubkey!(token_owner, "token_owner"),
token: parse_official_pubkey!(&token.0, "token"),
mint: parse_official_pubkey!(&mint.0, "mint"),
metadata: parse_official_pubkey!(&metadata.0, "metadata"),
edition: parse_optional_official_pubkey!(edition, "edition"),
token_record: parse_optional_official_pubkey!(token_record, "token_record"),
payer: parse_official_pubkey!(&intent.fee_payer.0, "fee_payer"),
system_program: parse_official_pubkey!(kb_program_ids::SYSTEM_PROGRAM_ID, "system_program"),
sysvar_instructions: parse_official_pubkey!(
kb_program_ids::SYSVAR_INSTRUCTIONS_PROGRAM_ID,
"sysvar_instructions"
),
spl_token_program: match spl_token_program {
std::option::Option::Some(v) => {
std::option::Option::Some(parse_official_pubkey!(&v.0, "spl_token_program"))
},
std::option::Option::None => std::option::Option::None,
},
authorization_rules_program: match authorization_rules_program {
std::option::Option::Some(v) => std::option::Option::Some(parse_official_pubkey!(
&v.0,
"authorization_rules_program"
)),
std::option::Option::None => std::option::Option::None,
},
authorization_rules: parse_optional_official_pubkey!(
authorization_rules,
"authorization_rules"
),
}
.instruction(mpl_token_metadata::instructions::LockInstructionArgs {
lock_args: lock_args.clone(),
});
return std::result::Result::Ok(convert_official_instruction!(official));
}
#[allow(clippy::too_many_arguments)]
fn build_unlock(
intent: &crate::ExMetaplexTokenMetadataExecutionIntent,
authority: &crate::MdPubkey,
token_owner: std::option::Option<&crate::MdPubkey>,
token: &crate::MdPubkey,
mint: &crate::MdPubkey,
metadata: &crate::MdPubkey,
edition: std::option::Option<&crate::MdPubkey>,
token_record: std::option::Option<&crate::MdPubkey>,
spl_token_program: std::option::Option<&crate::MdProgramId>,
authorization_rules_program: std::option::Option<&crate::MdProgramId>,
authorization_rules: std::option::Option<&crate::MdPubkey>,
unlock_args: &mpl_token_metadata::types::UnlockArgs,
) -> kb_core::Result<solana_instruction::Instruction> {
if let std::result::Result::Err(error) =
validate_rule_accounts(authorization_rules_program, authorization_rules)
{
return std::result::Result::Err(error);
}
let official = mpl_token_metadata::instructions::Unlock {
authority: parse_official_pubkey!(&authority.0, "authority"),
token_owner: parse_optional_official_pubkey!(token_owner, "token_owner"),
token: parse_official_pubkey!(&token.0, "token"),
mint: parse_official_pubkey!(&mint.0, "mint"),
metadata: parse_official_pubkey!(&metadata.0, "metadata"),
edition: parse_optional_official_pubkey!(edition, "edition"),
token_record: parse_optional_official_pubkey!(token_record, "token_record"),
payer: parse_official_pubkey!(&intent.fee_payer.0, "fee_payer"),
system_program: parse_official_pubkey!(kb_program_ids::SYSTEM_PROGRAM_ID, "system_program"),
sysvar_instructions: parse_official_pubkey!(
kb_program_ids::SYSVAR_INSTRUCTIONS_PROGRAM_ID,
"sysvar_instructions"
),
spl_token_program: match spl_token_program {
std::option::Option::Some(v) => {
std::option::Option::Some(parse_official_pubkey!(&v.0, "spl_token_program"))
},
std::option::Option::None => std::option::Option::None,
},
authorization_rules_program: match authorization_rules_program {
std::option::Option::Some(v) => std::option::Option::Some(parse_official_pubkey!(
&v.0,
"authorization_rules_program"
)),
std::option::Option::None => std::option::Option::None,
},
authorization_rules: parse_optional_official_pubkey!(
authorization_rules,
"authorization_rules"
),
}
.instruction(mpl_token_metadata::instructions::UnlockInstructionArgs {
unlock_args: unlock_args.clone(),
});
return std::result::Result::Ok(convert_official_instruction!(official));
}
#[allow(clippy::too_many_arguments)]
fn build_transfer(
intent: &crate::ExMetaplexTokenMetadataExecutionIntent,
token: &crate::MdPubkey,
token_owner: &crate::MdPubkey,
destination_token: &crate::MdPubkey,
destination_owner: &crate::MdPubkey,
mint: &crate::MdPubkey,
metadata: &crate::MdPubkey,
edition: std::option::Option<&crate::MdPubkey>,
token_record: std::option::Option<&crate::MdPubkey>,
destination_token_record: std::option::Option<&crate::MdPubkey>,
authority: &crate::MdPubkey,
authorization_rules_program: std::option::Option<&crate::MdProgramId>,
authorization_rules: std::option::Option<&crate::MdPubkey>,
transfer_args: &mpl_token_metadata::types::TransferArgs,
) -> kb_core::Result<solana_instruction::Instruction> {
if let std::result::Result::Err(error) =
validate_rule_accounts(authorization_rules_program, authorization_rules)
{
return std::result::Result::Err(error);
}
let official = mpl_token_metadata::instructions::Transfer {
token: parse_official_pubkey!(&token.0, "token"),
token_owner: parse_official_pubkey!(&token_owner.0, "token_owner"),
destination_token: parse_official_pubkey!(&destination_token.0, "destination_token"),
destination_owner: parse_official_pubkey!(&destination_owner.0, "destination_owner"),
mint: parse_official_pubkey!(&mint.0, "mint"),
metadata: parse_official_pubkey!(&metadata.0, "metadata"),
edition: parse_optional_official_pubkey!(edition, "edition"),
token_record: parse_optional_official_pubkey!(token_record, "token_record"),
destination_token_record: parse_optional_official_pubkey!(
destination_token_record,
"destination_token_record"
),
authority: parse_official_pubkey!(&authority.0, "authority"),
payer: parse_official_pubkey!(&intent.fee_payer.0, "fee_payer"),
system_program: parse_official_pubkey!(kb_program_ids::SYSTEM_PROGRAM_ID, "system_program"),
sysvar_instructions: parse_official_pubkey!(
kb_program_ids::SYSVAR_INSTRUCTIONS_PROGRAM_ID,
"sysvar_instructions"
),
spl_token_program: parse_official_pubkey!(
kb_program_ids::SPL_TOKEN_PROGRAM_ID,
"spl_token_program"
),
spl_ata_program: parse_official_pubkey!(
kb_program_ids::ASSOCIATED_TOKEN_PROGRAM_ID,
"spl_ata_program"
),
authorization_rules_program: match authorization_rules_program {
std::option::Option::Some(v) => std::option::Option::Some(parse_official_pubkey!(
&v.0,
"authorization_rules_program"
)),
std::option::Option::None => std::option::Option::None,
},
authorization_rules: parse_optional_official_pubkey!(
authorization_rules,
"authorization_rules"
),
}
.instruction(mpl_token_metadata::instructions::TransferInstructionArgs {
transfer_args: transfer_args.clone(),
});
return std::result::Result::Ok(convert_official_instruction!(official));
}
#[allow(clippy::too_many_arguments)]
fn build_burn(
authority: &crate::MdPubkey,
collection_metadata: std::option::Option<&crate::MdPubkey>,
metadata: &crate::MdPubkey,
edition: std::option::Option<&crate::MdPubkey>,
mint: &crate::MdPubkey,
token: &crate::MdPubkey,
master_edition: std::option::Option<&crate::MdPubkey>,
master_edition_mint: std::option::Option<&crate::MdPubkey>,
master_edition_token: std::option::Option<&crate::MdPubkey>,
edition_marker: std::option::Option<&crate::MdPubkey>,
token_record: std::option::Option<&crate::MdPubkey>,
burn_args: &mpl_token_metadata::types::BurnArgs,
) -> kb_core::Result<solana_instruction::Instruction> {
let official = mpl_token_metadata::instructions::Burn {
authority: parse_official_pubkey!(&authority.0, "authority"),
collection_metadata: parse_optional_official_pubkey!(
collection_metadata,
"collection_metadata"
),
metadata: parse_official_pubkey!(&metadata.0, "metadata"),
edition: parse_optional_official_pubkey!(edition, "edition"),
mint: parse_official_pubkey!(&mint.0, "mint"),
token: parse_official_pubkey!(&token.0, "token"),
master_edition: parse_optional_official_pubkey!(master_edition, "master_edition"),
master_edition_mint: parse_optional_official_pubkey!(
master_edition_mint,
"master_edition_mint"
),
master_edition_token: parse_optional_official_pubkey!(
master_edition_token,
"master_edition_token"
),
edition_marker: parse_optional_official_pubkey!(edition_marker, "edition_marker"),
token_record: parse_optional_official_pubkey!(token_record, "token_record"),
system_program: parse_official_pubkey!(kb_program_ids::SYSTEM_PROGRAM_ID, "system_program"),
sysvar_instructions: parse_official_pubkey!(
kb_program_ids::SYSVAR_INSTRUCTIONS_PROGRAM_ID,
"sysvar_instructions"
),
spl_token_program: parse_official_pubkey!(
kb_program_ids::SPL_TOKEN_PROGRAM_ID,
"spl_token_program"
),
}
.instruction(mpl_token_metadata::instructions::BurnInstructionArgs {
burn_args: burn_args.clone(),
});
return std::result::Result::Ok(convert_official_instruction!(official));
}
fn build_close_accounts(
metadata: &crate::MdPubkey,
edition: &crate::MdPubkey,
mint: &crate::MdPubkey,
authority: &crate::MdPubkey,
destination: &crate::MdPubkey,
) -> kb_core::Result<solana_instruction::Instruction> {
let official = mpl_token_metadata::instructions::CloseAccounts {
metadata: parse_official_pubkey!(&metadata.0, "metadata"),
edition: parse_official_pubkey!(&edition.0, "edition"),
mint: parse_official_pubkey!(&mint.0, "mint"),
authority: parse_official_pubkey!(&authority.0, "authority"),
destination: parse_official_pubkey!(&destination.0, "destination"),
}
.instruction();
return std::result::Result::Ok(convert_official_instruction!(official));
}
#[cfg(test)]
mod tests {
#[allow(deprecated)]
@@ -952,4 +1522,23 @@ mod tests {
);
}
}
#[test]
fn close_accounts_preserves_discriminator_and_exact_signer() {
let result = super::build_close_accounts(
&crate::MdPubkey("11111111111111111111111111111111".to_string()),
&crate::MdPubkey("SysvarRent111111111111111111111111111111111".to_string()),
&crate::MdPubkey("So11111111111111111111111111111111111111112".to_string()),
&crate::MdPubkey("Vote111111111111111111111111111111111111111".to_string()),
&crate::MdPubkey("Stake11111111111111111111111111111111111111".to_string()),
);
assert!(result.is_ok());
let instruction = match result {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
assert_eq!(instruction.data.first().copied(), std::option::Option::Some(57));
assert_eq!(instruction.accounts.len(), 5);
assert!(instruction.accounts[3].is_signer);
}
}

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/executor/metadata/metaplex_token_metadata/executor.rs
// version: 4
// version: 5
//! Exact Metaplex Token Metadata capability dispatch.
@@ -162,6 +162,12 @@ mod tests {
crate::EX_METAPLEX_TOKEN_METADATA_VERIFY_OPERATION,
);
assert!(matches!(supported, crate::ExApiExecutionCapability::Supported { .. }));
let transfer = <crate::ExMetadataMetaplexTokenMetadataExecutor as crate::ExApiTypedInstructionExecutor>::capability(
&executor,
&program_id,
crate::EX_METAPLEX_TOKEN_METADATA_TRANSFER_OPERATION,
);
assert!(matches!(transfer, crate::ExApiExecutionCapability::Supported { .. }));
let unknown = <crate::ExMetadataMetaplexTokenMetadataExecutor as crate::ExApiTypedInstructionExecutor>::capability(
&executor,
&program_id,

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/executor/metadata/metaplex_token_metadata/intent.rs
// version: 4
// version: 6
//! Typed current and deprecated Metaplex Token Metadata execution intents.
@@ -26,13 +26,32 @@ pub const EX_METAPLEX_TOKEN_METADATA_UNVERIFY_OPERATION: &str =
/// Stable deprecated operation code for SetCollectionSize, discriminator 34.
pub const EX_METAPLEX_TOKEN_METADATA_SET_COLLECTION_SIZE_OPERATION: &str =
"metadata.metaplex_token_metadata.set_collection_size";
/// Stable operation code for the current Burn wrapper, discriminator 41.
pub const EX_METAPLEX_TOKEN_METADATA_BURN_OPERATION: &str = "metadata.metaplex_token_metadata.burn";
/// Stable operation code for the current Delegate wrapper, discriminator 44.
pub const EX_METAPLEX_TOKEN_METADATA_DELEGATE_OPERATION: &str =
"metadata.metaplex_token_metadata.delegate";
/// Stable operation code for the current Revoke wrapper, discriminator 45.
pub const EX_METAPLEX_TOKEN_METADATA_REVOKE_OPERATION: &str =
"metadata.metaplex_token_metadata.revoke";
/// Stable operation code for the current Lock wrapper, discriminator 46.
pub const EX_METAPLEX_TOKEN_METADATA_LOCK_OPERATION: &str = "metadata.metaplex_token_metadata.lock";
/// Stable operation code for the current Unlock wrapper, discriminator 47.
pub const EX_METAPLEX_TOKEN_METADATA_UNLOCK_OPERATION: &str =
"metadata.metaplex_token_metadata.unlock";
/// Stable operation code for the current Transfer wrapper, discriminator 49.
pub const EX_METAPLEX_TOKEN_METADATA_TRANSFER_OPERATION: &str =
"metadata.metaplex_token_metadata.transfer";
/// Stable operation code for CloseAccounts, discriminator 57.
pub const EX_METAPLEX_TOKEN_METADATA_CLOSE_ACCOUNTS_OPERATION: &str =
"metadata.metaplex_token_metadata.close_accounts";
/// Deprecated operations that require explicit operator approval at runtime.
pub const EX_METAPLEX_TOKEN_METADATA_DEPRECATED_OPERATION_CODES: &[&str] = &[
EX_METAPLEX_TOKEN_METADATA_PUFF_METADATA_OPERATION,
EX_METAPLEX_TOKEN_METADATA_SET_TOKEN_STANDARD_OPERATION,
EX_METAPLEX_TOKEN_METADATA_SET_COLLECTION_SIZE_OPERATION,
];
/// Current and deprecated operations implemented through `0.4.7-pre.004`.
/// Current and deprecated operations implemented through `0.4.7-pre.005`.
pub const EX_METAPLEX_TOKEN_METADATA_SUPPORTED_OPERATION_CODES: &[&str] = &[
EX_METAPLEX_TOKEN_METADATA_CREATE_OPERATION,
EX_METAPLEX_TOKEN_METADATA_UPDATE_OPERATION,
@@ -41,6 +60,13 @@ pub const EX_METAPLEX_TOKEN_METADATA_SUPPORTED_OPERATION_CODES: &[&str] = &[
EX_METAPLEX_TOKEN_METADATA_VERIFY_OPERATION,
EX_METAPLEX_TOKEN_METADATA_UNVERIFY_OPERATION,
EX_METAPLEX_TOKEN_METADATA_SET_COLLECTION_SIZE_OPERATION,
EX_METAPLEX_TOKEN_METADATA_BURN_OPERATION,
EX_METAPLEX_TOKEN_METADATA_DELEGATE_OPERATION,
EX_METAPLEX_TOKEN_METADATA_REVOKE_OPERATION,
EX_METAPLEX_TOKEN_METADATA_LOCK_OPERATION,
EX_METAPLEX_TOKEN_METADATA_UNLOCK_OPERATION,
EX_METAPLEX_TOKEN_METADATA_TRANSFER_OPERATION,
EX_METAPLEX_TOKEN_METADATA_CLOSE_ACCOUNTS_OPERATION,
];
/// One current or explicitly deprecated Metaplex Token Metadata operation.
@@ -168,6 +194,116 @@ pub enum ExMetaplexTokenMetadataOperation {
/// New collection size.
size: u64,
},
#[allow(missing_docs)]
/// Build the current Burn wrapper.
Burn {
authority: crate::MdPubkey,
collection_metadata: std::option::Option<crate::MdPubkey>,
metadata: crate::MdPubkey,
edition: std::option::Option<crate::MdPubkey>,
mint: crate::MdPubkey,
token: crate::MdPubkey,
master_edition: std::option::Option<crate::MdPubkey>,
master_edition_mint: std::option::Option<crate::MdPubkey>,
master_edition_token: std::option::Option<crate::MdPubkey>,
edition_marker: std::option::Option<crate::MdPubkey>,
token_record: std::option::Option<crate::MdPubkey>,
#[ts(type = "unknown")]
burn_args: mpl_token_metadata::types::BurnArgs,
},
#[allow(missing_docs)]
/// Build the current unified Delegate wrapper.
Delegate {
delegate_record: std::option::Option<crate::MdPubkey>,
delegate: crate::MdPubkey,
metadata: crate::MdPubkey,
master_edition: std::option::Option<crate::MdPubkey>,
token_record: std::option::Option<crate::MdPubkey>,
mint: crate::MdPubkey,
token: std::option::Option<crate::MdPubkey>,
authority: crate::MdPubkey,
spl_token_program: std::option::Option<crate::MdProgramId>,
authorization_rules_program: std::option::Option<crate::MdProgramId>,
authorization_rules: std::option::Option<crate::MdPubkey>,
#[ts(type = "unknown")]
delegate_args: mpl_token_metadata::types::DelegateArgs,
},
#[allow(missing_docs)]
/// Build the current unified Revoke wrapper.
Revoke {
delegate_record: std::option::Option<crate::MdPubkey>,
delegate: crate::MdPubkey,
metadata: crate::MdPubkey,
master_edition: std::option::Option<crate::MdPubkey>,
token_record: std::option::Option<crate::MdPubkey>,
mint: crate::MdPubkey,
token: std::option::Option<crate::MdPubkey>,
authority: crate::MdPubkey,
spl_token_program: std::option::Option<crate::MdProgramId>,
authorization_rules_program: std::option::Option<crate::MdProgramId>,
authorization_rules: std::option::Option<crate::MdPubkey>,
#[ts(type = "unknown")]
revoke_args: mpl_token_metadata::types::RevokeArgs,
},
#[allow(missing_docs)]
/// Build the current Lock wrapper.
Lock {
authority: crate::MdPubkey,
token_owner: std::option::Option<crate::MdPubkey>,
token: crate::MdPubkey,
mint: crate::MdPubkey,
metadata: crate::MdPubkey,
edition: std::option::Option<crate::MdPubkey>,
token_record: std::option::Option<crate::MdPubkey>,
spl_token_program: std::option::Option<crate::MdProgramId>,
authorization_rules_program: std::option::Option<crate::MdProgramId>,
authorization_rules: std::option::Option<crate::MdPubkey>,
#[ts(type = "unknown")]
lock_args: mpl_token_metadata::types::LockArgs,
},
#[allow(missing_docs)]
/// Build the current Unlock wrapper.
Unlock {
authority: crate::MdPubkey,
token_owner: std::option::Option<crate::MdPubkey>,
token: crate::MdPubkey,
mint: crate::MdPubkey,
metadata: crate::MdPubkey,
edition: std::option::Option<crate::MdPubkey>,
token_record: std::option::Option<crate::MdPubkey>,
spl_token_program: std::option::Option<crate::MdProgramId>,
authorization_rules_program: std::option::Option<crate::MdProgramId>,
authorization_rules: std::option::Option<crate::MdPubkey>,
#[ts(type = "unknown")]
unlock_args: mpl_token_metadata::types::UnlockArgs,
},
#[allow(missing_docs)]
/// Build the current Transfer wrapper.
Transfer {
token: crate::MdPubkey,
token_owner: crate::MdPubkey,
destination_token: crate::MdPubkey,
destination_owner: crate::MdPubkey,
mint: crate::MdPubkey,
metadata: crate::MdPubkey,
edition: std::option::Option<crate::MdPubkey>,
token_record: std::option::Option<crate::MdPubkey>,
destination_token_record: std::option::Option<crate::MdPubkey>,
authority: crate::MdPubkey,
authorization_rules_program: std::option::Option<crate::MdProgramId>,
authorization_rules: std::option::Option<crate::MdPubkey>,
#[ts(type = "unknown")]
transfer_args: mpl_token_metadata::types::TransferArgs,
},
#[allow(missing_docs)]
/// Close ownerless metadata and edition accounts.
CloseAccounts {
metadata: crate::MdPubkey,
edition: crate::MdPubkey,
mint: crate::MdPubkey,
authority: crate::MdPubkey,
destination: crate::MdPubkey,
},
}
#[allow(deprecated)]
@@ -188,6 +324,15 @@ impl crate::ExMetaplexTokenMetadataOperation {
Self::SetCollectionSize { .. } => {
crate::EX_METAPLEX_TOKEN_METADATA_SET_COLLECTION_SIZE_OPERATION
},
Self::Burn { .. } => crate::EX_METAPLEX_TOKEN_METADATA_BURN_OPERATION,
Self::Delegate { .. } => crate::EX_METAPLEX_TOKEN_METADATA_DELEGATE_OPERATION,
Self::Revoke { .. } => crate::EX_METAPLEX_TOKEN_METADATA_REVOKE_OPERATION,
Self::Lock { .. } => crate::EX_METAPLEX_TOKEN_METADATA_LOCK_OPERATION,
Self::Unlock { .. } => crate::EX_METAPLEX_TOKEN_METADATA_UNLOCK_OPERATION,
Self::Transfer { .. } => crate::EX_METAPLEX_TOKEN_METADATA_TRANSFER_OPERATION,
Self::CloseAccounts { .. } => {
crate::EX_METAPLEX_TOKEN_METADATA_CLOSE_ACCOUNTS_OPERATION
},
};
}
@@ -228,7 +373,7 @@ mod tests {
#[test]
#[allow(deprecated)]
fn operation_codes_are_exact_unique_and_partition_deprecated_operations() {
assert_eq!(crate::EX_METAPLEX_TOKEN_METADATA_SUPPORTED_OPERATION_CODES.len(), 7);
assert_eq!(crate::EX_METAPLEX_TOKEN_METADATA_SUPPORTED_OPERATION_CODES.len(), 14);
let mut unique = std::collections::BTreeSet::new();
for operation_code in crate::EX_METAPLEX_TOKEN_METADATA_SUPPORTED_OPERATION_CODES {
assert!(unique.insert(*operation_code));

View File

@@ -1,5 +1,5 @@
// file: kb-lib/src/lib.rs
// version: 29
// version: 28
//! Consolidated decoder, executor, materializer and shared model library.
#![warn(missing_docs)]
@@ -358,18 +358,32 @@ pub use self::decoder::decoder_metadata_metaplex_token_metadata_decode_use_autho
pub use self::decoder::decoder_spl_elgamal_registry_parse_elgamal_registry_state;
/// Parses one Token-2022 Mint, Account, or Multisig state.
pub use self::decoder::decoder_spl_token_2022_parse_token_2022_state;
/// Stable Metaplex Token Metadata burn operation code.
pub use self::executor::EX_METAPLEX_TOKEN_METADATA_BURN_OPERATION;
/// Stable Metaplex Token Metadata close_accounts operation code.
pub use self::executor::EX_METAPLEX_TOKEN_METADATA_CLOSE_ACCOUNTS_OPERATION;
/// Stable operation code for the current Metaplex Create wrapper.
pub use self::executor::EX_METAPLEX_TOKEN_METADATA_CREATE_OPERATION;
/// Stable Metaplex Token Metadata delegate operation code.
pub use self::executor::EX_METAPLEX_TOKEN_METADATA_DELEGATE_OPERATION;
/// Deprecated Metaplex operation codes requiring explicit approval.
pub use self::executor::EX_METAPLEX_TOKEN_METADATA_DEPRECATED_OPERATION_CODES;
/// Stable Metaplex Token Metadata lock operation code.
pub use self::executor::EX_METAPLEX_TOKEN_METADATA_LOCK_OPERATION;
/// Stable deprecated Metaplex PuffMetadata operation code.
pub use self::executor::EX_METAPLEX_TOKEN_METADATA_PUFF_METADATA_OPERATION;
/// Stable Metaplex Token Metadata revoke operation code.
pub use self::executor::EX_METAPLEX_TOKEN_METADATA_REVOKE_OPERATION;
/// Stable deprecated Metaplex SetCollectionSize operation code.
pub use self::executor::EX_METAPLEX_TOKEN_METADATA_SET_COLLECTION_SIZE_OPERATION;
/// Stable deprecated Metaplex SetTokenStandard operation code.
pub use self::executor::EX_METAPLEX_TOKEN_METADATA_SET_TOKEN_STANDARD_OPERATION;
/// Current and deprecated Metaplex Token Metadata operations.
pub use self::executor::EX_METAPLEX_TOKEN_METADATA_SUPPORTED_OPERATION_CODES;
/// Stable Metaplex Token Metadata transfer operation code.
pub use self::executor::EX_METAPLEX_TOKEN_METADATA_TRANSFER_OPERATION;
/// Stable Metaplex Token Metadata unlock operation code.
pub use self::executor::EX_METAPLEX_TOKEN_METADATA_UNLOCK_OPERATION;
/// Stable operation code for the current Metaplex Unverify wrapper.
pub use self::executor::EX_METAPLEX_TOKEN_METADATA_UNVERIFY_OPERATION;
/// Stable operation code for the current Metaplex Update wrapper.