v0.4.8-pre.011
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/decoder.rs
|
||||
// version: 16
|
||||
// version: 17
|
||||
|
||||
//! Consolidated decoder modules.
|
||||
|
||||
@@ -745,6 +745,8 @@ pub(crate) use self::spl::decoder_spl_token_2022_decode;
|
||||
pub(crate) use self::spl::decoder_spl_token_2022_entry_for_tag;
|
||||
/// Parses one Token-2022 Mint, Account, or Multisig state.
|
||||
pub use self::spl::decoder_spl_token_2022_parse_token_2022_state;
|
||||
/// Parses one exact Token Metadata interface value.
|
||||
pub use self::spl::decoder_spl_token_2022_parse_token_metadata_value;
|
||||
/// Returns the first byte of one retained Token-2022 payload.
|
||||
pub(crate) use self::spl::decoder_spl_token_2022_payload_tag;
|
||||
/// Decodes one bounded classic SPL Token instruction.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/decoder/spl.rs
|
||||
// version: 10
|
||||
// version: 11
|
||||
|
||||
//! `spl` decoder family.
|
||||
|
||||
@@ -147,5 +147,7 @@ pub(crate) use self::token_2022::decoder_spl_token_2022_decode;
|
||||
pub(crate) use self::token_2022::decoder_spl_token_2022_entry_for_tag;
|
||||
/// Parses one Token-2022 Mint, Account, or Multisig state.
|
||||
pub use self::token_2022::decoder_spl_token_2022_parse_token_2022_state;
|
||||
/// Parses one exact Token Metadata interface value.
|
||||
pub use self::token_2022::decoder_spl_token_2022_parse_token_metadata_value;
|
||||
/// Returns the first byte of one retained Token-2022 payload.
|
||||
pub(crate) use self::token_2022::decoder_spl_token_2022_payload_tag;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/decoder/spl/token_2022.rs
|
||||
// version: 4
|
||||
// version: 5
|
||||
|
||||
//! Exact Token-2022 instruction and state decoder component.
|
||||
|
||||
@@ -18,6 +18,8 @@ pub use self::state::DcToken2022StateKind;
|
||||
pub use self::state::DcToken2022TlvEntry;
|
||||
/// Parses one Token-2022 Mint, Account, or Multisig state.
|
||||
pub use self::state::decoder_spl_token_2022_parse_token_2022_state;
|
||||
/// Parses one exact Token Metadata interface value.
|
||||
pub use self::state::decoder_spl_token_2022_parse_token_metadata_value;
|
||||
|
||||
/// Maximum prefix retained in bounded Token-2022 diagnostics.
|
||||
pub(crate) use self::constants::DC_SPL_TOKEN_2022_DIAGNOSTIC_PREFIX_BYTES;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/decoder/spl/token_2022/state.rs
|
||||
// version: 3
|
||||
// version: 4
|
||||
|
||||
//! Strict Token-2022 base-state and TLV parsing.
|
||||
|
||||
@@ -429,6 +429,13 @@ fn decode_token_group_member(value: &[u8]) -> Result<serde_json::Value, String>
|
||||
}));
|
||||
}
|
||||
|
||||
/// Parses one exact Token Metadata interface value with full-consumption checks.
|
||||
pub fn decoder_spl_token_2022_parse_token_metadata_value(
|
||||
value: &[u8],
|
||||
) -> std::result::Result<serde_json::Value, std::string::String> {
|
||||
return decode_token_metadata(value);
|
||||
}
|
||||
|
||||
fn decode_token_metadata(value: &[u8]) -> Result<serde_json::Value, String> {
|
||||
if value.len() < 76 {
|
||||
return Err(format!(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/executor.rs
|
||||
// version: 16
|
||||
// version: 17
|
||||
|
||||
//! Consolidated executor modules.
|
||||
|
||||
@@ -714,6 +714,8 @@ pub use self::spl::EX_SPL_TOKEN_2022_DISABLE_REQUIRED_TRANSFER_MEMOS_OPERATION;
|
||||
pub use self::spl::EX_SPL_TOKEN_2022_ELGAMAL_CIPHERTEXT_BYTES;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_ELGAMAL_PUBKEY_BYTES`.
|
||||
pub use self::spl::EX_SPL_TOKEN_2022_ELGAMAL_PUBKEY_BYTES;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_EMIT_TOKEN_METADATA_OPERATION`.
|
||||
pub use self::spl::EX_SPL_TOKEN_2022_EMIT_TOKEN_METADATA_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_EMPTY_CONFIDENTIAL_TRANSFER_ACCOUNT_OPERATION`.
|
||||
pub use self::spl::EX_SPL_TOKEN_2022_EMPTY_CONFIDENTIAL_TRANSFER_ACCOUNT_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_ENABLE_CONFIDENTIAL_CREDITS_OPERATION`.
|
||||
@@ -844,6 +846,8 @@ pub use self::spl::EX_SPL_TOKEN_2022_UPDATE_METADATA_POINTER_OPERATION;
|
||||
pub use self::spl::EX_SPL_TOKEN_2022_UPDATE_SCALED_UI_AMOUNT_MULTIPLIER_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_UPDATE_TOKEN_GROUP_MAX_SIZE_OPERATION`.
|
||||
pub use self::spl::EX_SPL_TOKEN_2022_UPDATE_TOKEN_GROUP_MAX_SIZE_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_AUTHORITY_OPERATION`.
|
||||
pub use self::spl::EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_AUTHORITY_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_FIELD_OPERATION`.
|
||||
pub use self::spl::EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_FIELD_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_UPDATE_TRANSFER_HOOK_OPERATION`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/executor/api/execution.rs
|
||||
// version: 8
|
||||
// version: 9
|
||||
|
||||
//! Typed execution plans, policies and result contracts.
|
||||
|
||||
@@ -378,6 +378,9 @@ pub struct ExApiExecutionSimulationResult {
|
||||
pub estimated_fee_lamports: std::option::Option<u64>,
|
||||
/// Simulation logs in runtime order.
|
||||
pub logs: std::vec::Vec<std::string::String>,
|
||||
/// Program return data retained as provider-neutral JSON when reported.
|
||||
#[serde(default)]
|
||||
pub return_data: std::option::Option<serde_json::Value>,
|
||||
/// Stable or provider error text when simulation failed.
|
||||
pub error: std::option::Option<std::string::String>,
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/executor/safety/evaluation.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
//! Safety checks applied before simulation, signing or sending.
|
||||
|
||||
@@ -516,6 +516,7 @@ mod tests {
|
||||
units_consumed: std::option::Option::Some(500),
|
||||
estimated_fee_lamports: std::option::Option::Some(5_000),
|
||||
logs: std::vec::Vec::new(),
|
||||
return_data: std::option::Option::None,
|
||||
error: std::option::Option::None,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/executor/solana/transaction/core.rs
|
||||
// version: 9
|
||||
// version: 10
|
||||
|
||||
//! Legacy and durable nonce Solana transaction assembly, simulation binding and signing.
|
||||
|
||||
@@ -750,6 +750,7 @@ mod tests {
|
||||
units_consumed: std::option::Option::Some(500),
|
||||
estimated_fee_lamports: std::option::Option::Some(5_000),
|
||||
logs: std::vec::Vec::new(),
|
||||
return_data: std::option::Option::None,
|
||||
error: std::option::Option::None,
|
||||
};
|
||||
}
|
||||
@@ -773,6 +774,7 @@ mod tests {
|
||||
units_consumed: std::option::Option::Some(700),
|
||||
estimated_fee_lamports: std::option::Option::Some(10_000),
|
||||
logs: std::vec::Vec::new(),
|
||||
return_data: std::option::Option::None,
|
||||
error: std::option::Option::None,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/executor/spl.rs
|
||||
// version: 7
|
||||
// version: 8
|
||||
|
||||
//! `spl` executor family.
|
||||
|
||||
@@ -183,6 +183,8 @@ pub use self::token_2022::EX_SPL_TOKEN_2022_DISABLE_REQUIRED_TRANSFER_MEMOS_OPER
|
||||
pub use self::token_2022::EX_SPL_TOKEN_2022_ELGAMAL_CIPHERTEXT_BYTES;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_ELGAMAL_PUBKEY_BYTES`.
|
||||
pub use self::token_2022::EX_SPL_TOKEN_2022_ELGAMAL_PUBKEY_BYTES;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_EMIT_TOKEN_METADATA_OPERATION`.
|
||||
pub use self::token_2022::EX_SPL_TOKEN_2022_EMIT_TOKEN_METADATA_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_EMPTY_CONFIDENTIAL_TRANSFER_ACCOUNT_OPERATION`.
|
||||
pub use self::token_2022::EX_SPL_TOKEN_2022_EMPTY_CONFIDENTIAL_TRANSFER_ACCOUNT_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_ENABLE_CONFIDENTIAL_CREDITS_OPERATION`.
|
||||
@@ -313,6 +315,8 @@ pub use self::token_2022::EX_SPL_TOKEN_2022_UPDATE_METADATA_POINTER_OPERATION;
|
||||
pub use self::token_2022::EX_SPL_TOKEN_2022_UPDATE_SCALED_UI_AMOUNT_MULTIPLIER_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_UPDATE_TOKEN_GROUP_MAX_SIZE_OPERATION`.
|
||||
pub use self::token_2022::EX_SPL_TOKEN_2022_UPDATE_TOKEN_GROUP_MAX_SIZE_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_AUTHORITY_OPERATION`.
|
||||
pub use self::token_2022::EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_AUTHORITY_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_FIELD_OPERATION`.
|
||||
pub use self::token_2022::EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_FIELD_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_UPDATE_TRANSFER_HOOK_OPERATION`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/executor/spl/token_2022.rs
|
||||
// version: 5
|
||||
// version: 6
|
||||
|
||||
//! SPL Token-2022 executor.
|
||||
|
||||
@@ -86,6 +86,8 @@ pub use self::intent::EX_SPL_TOKEN_2022_DISABLE_CPI_GUARD_OPERATION;
|
||||
pub use self::intent::EX_SPL_TOKEN_2022_DISABLE_NON_CONFIDENTIAL_CREDITS_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_DISABLE_REQUIRED_TRANSFER_MEMOS_OPERATION`.
|
||||
pub use self::intent::EX_SPL_TOKEN_2022_DISABLE_REQUIRED_TRANSFER_MEMOS_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_EMIT_TOKEN_METADATA_OPERATION`.
|
||||
pub use self::intent::EX_SPL_TOKEN_2022_EMIT_TOKEN_METADATA_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_EMPTY_CONFIDENTIAL_TRANSFER_ACCOUNT_OPERATION`.
|
||||
pub use self::intent::EX_SPL_TOKEN_2022_EMPTY_CONFIDENTIAL_TRANSFER_ACCOUNT_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_ENABLE_CONFIDENTIAL_CREDITS_OPERATION`.
|
||||
@@ -214,6 +216,8 @@ pub use self::intent::EX_SPL_TOKEN_2022_UPDATE_METADATA_POINTER_OPERATION;
|
||||
pub use self::intent::EX_SPL_TOKEN_2022_UPDATE_SCALED_UI_AMOUNT_MULTIPLIER_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_UPDATE_TOKEN_GROUP_MAX_SIZE_OPERATION`.
|
||||
pub use self::intent::EX_SPL_TOKEN_2022_UPDATE_TOKEN_GROUP_MAX_SIZE_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_AUTHORITY_OPERATION`.
|
||||
pub use self::intent::EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_AUTHORITY_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_FIELD_OPERATION`.
|
||||
pub use self::intent::EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_FIELD_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_UPDATE_TRANSFER_HOOK_OPERATION`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/executor/spl/token_2022/builder.rs
|
||||
// version: 30
|
||||
// version: 34
|
||||
|
||||
//! Official Token-2022 builders and conservative plan validation.
|
||||
|
||||
@@ -172,6 +172,41 @@ fn validate_metadata_string(value: &str, field: &str) -> kb_core::Result<()> {
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
|
||||
fn validate_token_metadata_emit_range(
|
||||
start: std::option::Option<u64>,
|
||||
end: std::option::Option<u64>,
|
||||
) -> kb_core::Result<()> {
|
||||
if let (std::option::Option::Some(start), std::option::Option::Some(end)) = (start, end) {
|
||||
if start > end {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_spl_token_2022_metadata_emit_range_invalid",
|
||||
format!("Token metadata Emit start {start} exceeds end {end}"),
|
||||
));
|
||||
}
|
||||
if end - start > 1_024 {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_spl_token_2022_metadata_emit_range_too_large",
|
||||
"Token metadata Emit range exceeds the 1024-byte Solana return-data bound",
|
||||
));
|
||||
}
|
||||
}
|
||||
if let (std::option::Option::None, std::option::Option::Some(end)) = (start, end) {
|
||||
if end > 1_024 {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_spl_token_2022_metadata_emit_range_too_large",
|
||||
"Token metadata Emit range from zero exceeds the 1024-byte Solana return-data bound",
|
||||
));
|
||||
}
|
||||
}
|
||||
if let (std::option::Option::Some(_), std::option::Option::None) = (start, end) {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_spl_token_2022_metadata_emit_range_end_required",
|
||||
"Token metadata Emit with a start offset requires an explicit end to remain bounded",
|
||||
));
|
||||
}
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
|
||||
fn default_account_state(
|
||||
state: crate::ExSplTokenDefaultAccountState,
|
||||
) -> spl_token_2022_interface::state::AccountState {
|
||||
@@ -1162,6 +1197,40 @@ fn build_single(
|
||||
*idempotent,
|
||||
))
|
||||
},
|
||||
crate::ExSplTokenSingleOperation::UpdateTokenMetadataAuthority {
|
||||
metadata,
|
||||
current_authority,
|
||||
new_authority,
|
||||
} => {
|
||||
let metadata = parse_key!(metadata, "metadata");
|
||||
let current_authority = parse_key!(current_authority, "current_authority");
|
||||
let new_authority = parse_optional_key!(new_authority, "new_authority");
|
||||
let nullable_authority = match new_authority.try_into() {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_spl_token_2022_metadata_authority_invalid",
|
||||
"Token metadata authority cannot be encoded as a nullable address",
|
||||
));
|
||||
},
|
||||
};
|
||||
std::result::Result::Ok(spl_token_metadata_interface::instruction::update_authority(
|
||||
program_id,
|
||||
&metadata,
|
||||
¤t_authority,
|
||||
nullable_authority,
|
||||
))
|
||||
},
|
||||
crate::ExSplTokenSingleOperation::EmitTokenMetadata { metadata, start, end } => {
|
||||
match validate_token_metadata_emit_range(*start, *end) {
|
||||
std::result::Result::Ok(()) => {},
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
}
|
||||
let metadata = parse_key!(metadata, "metadata");
|
||||
std::result::Result::Ok(spl_token_metadata_interface::instruction::emit(
|
||||
program_id, &metadata, *start, *end,
|
||||
))
|
||||
},
|
||||
crate::ExSplTokenSingleOperation::InitializeTokenGroup {
|
||||
group,
|
||||
mint,
|
||||
@@ -3566,6 +3635,22 @@ pub(crate) mod tests {
|
||||
idempotent: true,
|
||||
},
|
||||
),
|
||||
(
|
||||
255,
|
||||
crate::ExSplTokenSingleOperation::UpdateTokenMetadataAuthority {
|
||||
metadata: first.clone(),
|
||||
current_authority: second.clone(),
|
||||
new_authority: std::option::Option::Some(third.clone()),
|
||||
},
|
||||
),
|
||||
(
|
||||
255,
|
||||
crate::ExSplTokenSingleOperation::EmitTokenMetadata {
|
||||
metadata: first.clone(),
|
||||
start: std::option::Option::Some(0),
|
||||
end: std::option::Option::Some(64),
|
||||
},
|
||||
),
|
||||
(
|
||||
255,
|
||||
crate::ExSplTokenSingleOperation::InitializeTokenGroup {
|
||||
@@ -4706,6 +4791,7 @@ pub(crate) mod tests {
|
||||
uri: std::string::String::from("https://example.invalid/token.json"),
|
||||
},
|
||||
4_usize,
|
||||
true,
|
||||
),
|
||||
(
|
||||
crate::ExSplTokenSingleOperation::UpdateTokenMetadataField {
|
||||
@@ -4717,6 +4803,7 @@ pub(crate) mod tests {
|
||||
value: std::string::String::from("https://example.invalid"),
|
||||
},
|
||||
2_usize,
|
||||
true,
|
||||
),
|
||||
(
|
||||
crate::ExSplTokenSingleOperation::RemoveTokenMetadataKey {
|
||||
@@ -4726,6 +4813,25 @@ pub(crate) mod tests {
|
||||
idempotent: true,
|
||||
},
|
||||
2_usize,
|
||||
true,
|
||||
),
|
||||
(
|
||||
crate::ExSplTokenSingleOperation::UpdateTokenMetadataAuthority {
|
||||
metadata: first.clone(),
|
||||
current_authority: second.clone(),
|
||||
new_authority: std::option::Option::Some(third.clone()),
|
||||
},
|
||||
2_usize,
|
||||
true,
|
||||
),
|
||||
(
|
||||
crate::ExSplTokenSingleOperation::EmitTokenMetadata {
|
||||
metadata: first.clone(),
|
||||
start: std::option::Option::Some(8),
|
||||
end: std::option::Option::Some(72),
|
||||
},
|
||||
1_usize,
|
||||
false,
|
||||
),
|
||||
(
|
||||
crate::ExSplTokenSingleOperation::InitializeTokenGroup {
|
||||
@@ -4736,6 +4842,7 @@ pub(crate) mod tests {
|
||||
max_size: 42,
|
||||
},
|
||||
3_usize,
|
||||
true,
|
||||
),
|
||||
(
|
||||
crate::ExSplTokenSingleOperation::UpdateTokenGroupMaxSize {
|
||||
@@ -4744,6 +4851,7 @@ pub(crate) mod tests {
|
||||
max_size: 84,
|
||||
},
|
||||
2_usize,
|
||||
true,
|
||||
),
|
||||
(
|
||||
crate::ExSplTokenSingleOperation::InitializeTokenGroupMember {
|
||||
@@ -4754,9 +4862,10 @@ pub(crate) mod tests {
|
||||
group_update_authority: second,
|
||||
},
|
||||
5_usize,
|
||||
true,
|
||||
),
|
||||
];
|
||||
for (operation, account_count) in cases {
|
||||
for (operation, account_count, first_writable) in cases {
|
||||
let intent = intent(crate::ExSplToken2022Operation::Instruction {
|
||||
value: std::boxed::Box::new(operation),
|
||||
});
|
||||
@@ -4767,7 +4876,63 @@ pub(crate) mod tests {
|
||||
.unwrap_or_else(|error| panic!("metadata or group plan failed: {error}"));
|
||||
assert!(plan.instructions[0].data.len() >= 8);
|
||||
assert_eq!(plan.instructions[0].accounts.len(), account_count);
|
||||
assert!(plan.instructions[0].accounts[0].is_writable);
|
||||
assert_eq!(plan.instructions[0].accounts[0].is_writable, first_writable);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn metadata_update_authority_accepts_nullable_none() {
|
||||
let planned = planned_single_instruction(
|
||||
crate::ExSplTokenSingleOperation::UpdateTokenMetadataAuthority {
|
||||
metadata: pubkey(kb_program_ids::SYSTEM_PROGRAM_ID),
|
||||
current_authority: pubkey(kb_program_ids::CONFIG_PROGRAM_ID),
|
||||
new_authority: std::option::Option::None,
|
||||
},
|
||||
);
|
||||
assert_eq!(planned.operation_code, "spl.token_2022.update_token_metadata_authority");
|
||||
assert_eq!(planned.accounts.len(), 2);
|
||||
assert!(planned.accounts[0].is_writable);
|
||||
assert!(planned.accounts[1].is_signer);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn metadata_emit_accepts_complete_and_maximum_bounded_ranges() {
|
||||
for (start, end) in [
|
||||
(std::option::Option::None, std::option::Option::None),
|
||||
(std::option::Option::Some(0), std::option::Option::Some(1_024)),
|
||||
] {
|
||||
let planned =
|
||||
planned_single_instruction(crate::ExSplTokenSingleOperation::EmitTokenMetadata {
|
||||
metadata: pubkey(kb_program_ids::SYSTEM_PROGRAM_ID),
|
||||
start,
|
||||
end,
|
||||
});
|
||||
assert_eq!(planned.operation_code, "spl.token_2022.emit_token_metadata");
|
||||
assert_eq!(planned.accounts.len(), 1);
|
||||
assert!(!planned.accounts[0].is_writable);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn metadata_emit_rejects_reversed_oversized_and_open_ended_ranges() {
|
||||
let metadata = pubkey(kb_program_ids::SYSTEM_PROGRAM_ID);
|
||||
for (start, end) in [
|
||||
(std::option::Option::Some(9), std::option::Option::Some(8)),
|
||||
(std::option::Option::Some(0), std::option::Option::Some(1_025)),
|
||||
(std::option::Option::Some(1), std::option::Option::None),
|
||||
] {
|
||||
let value = crate::ExSplTokenSingleOperation::EmitTokenMetadata {
|
||||
metadata: metadata.clone(),
|
||||
start,
|
||||
end,
|
||||
};
|
||||
let result = crate::ExApiTypedInstructionExecutor::build_prepared_plan(
|
||||
&crate::ExSplToken2022Executor,
|
||||
&intent(crate::ExSplToken2022Operation::Instruction {
|
||||
value: std::boxed::Box::new(value),
|
||||
}),
|
||||
);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/executor/spl/token_2022/executor.rs
|
||||
// version: 23
|
||||
// version: 25
|
||||
|
||||
//! Exact Token-2022 capability dispatch and typed plan construction.
|
||||
|
||||
@@ -220,6 +220,86 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
fn matrix_operation_name(name: &str) -> &str {
|
||||
return match name {
|
||||
"initialize_interest_bearing_mint" | "update_interest_bearing_rate" => {
|
||||
"interest_bearing_mint_extension"
|
||||
},
|
||||
"initialize_transfer_fee_config"
|
||||
| "set_transfer_fee"
|
||||
| "transfer_checked_with_fee"
|
||||
| "withdraw_withheld_tokens_from_mint"
|
||||
| "withdraw_withheld_tokens_from_accounts"
|
||||
| "harvest_withheld_tokens_to_mint" => "transfer_fee_extension",
|
||||
"initialize_default_account_state" | "update_default_account_state" => {
|
||||
"default_account_state_extension"
|
||||
},
|
||||
"enable_required_transfer_memos" | "disable_required_transfer_memos" => {
|
||||
"memo_transfer_extension"
|
||||
},
|
||||
"enable_cpi_guard" | "disable_cpi_guard" => "cpi_guard_extension",
|
||||
"initialize_transfer_hook" | "update_transfer_hook" => "transfer_hook_extension",
|
||||
"initialize_metadata_pointer" | "update_metadata_pointer" => {
|
||||
"metadata_pointer_extension"
|
||||
},
|
||||
"initialize_group_pointer" | "update_group_pointer" => "group_pointer_extension",
|
||||
"initialize_group_member_pointer" | "update_group_member_pointer" => {
|
||||
"group_member_pointer_extension"
|
||||
},
|
||||
"initialize_token_metadata"
|
||||
| "update_token_metadata_field"
|
||||
| "remove_token_metadata_key"
|
||||
| "update_token_metadata_authority"
|
||||
| "emit_token_metadata" => "token_metadata",
|
||||
"initialize_token_group" | "update_token_group_max_size" => "token_group",
|
||||
"initialize_token_group_member" => "token_group_member",
|
||||
"initialize_scaled_ui_amount" | "update_scaled_ui_amount_multiplier" => {
|
||||
"scaled_ui_amount_extension"
|
||||
},
|
||||
"initialize_pausable_config" | "pause" | "resume" => "pausable_extension",
|
||||
"initialize_permissioned_burn"
|
||||
| "permissioned_burn"
|
||||
| "permissioned_burn_checked"
|
||||
| "permissioned_confidential_burn" => "permissioned_burn_extension",
|
||||
"initialize_confidential_transfer_mint"
|
||||
| "update_confidential_transfer_mint"
|
||||
| "apply_pending_confidential_balance"
|
||||
| "approve_confidential_transfer_account"
|
||||
| "deposit_confidential_tokens"
|
||||
| "enable_confidential_credits"
|
||||
| "disable_confidential_credits"
|
||||
| "enable_non_confidential_credits"
|
||||
| "disable_non_confidential_credits"
|
||||
| "configure_confidential_transfer_account"
|
||||
| "configure_confidential_transfer_account_with_registry"
|
||||
| "empty_confidential_transfer_account"
|
||||
| "withdraw_confidential_tokens"
|
||||
| "transfer_confidential_tokens"
|
||||
| "transfer_confidential_tokens_with_fee" => "confidential_transfer_extension",
|
||||
"initialize_confidential_transfer_fee_config"
|
||||
| "enable_confidential_transfer_fee_harvest"
|
||||
| "disable_confidential_transfer_fee_harvest"
|
||||
| "harvest_confidential_withheld_tokens_to_mint"
|
||||
| "withdraw_confidential_withheld_tokens_from_mint"
|
||||
| "withdraw_confidential_withheld_tokens_from_accounts" => {
|
||||
"confidential_transfer_fee_extension"
|
||||
},
|
||||
"initialize_confidential_mint_burn_mint"
|
||||
| "rotate_confidential_supply_elgamal_pubkey"
|
||||
| "update_confidential_decryptable_supply"
|
||||
| "apply_pending_confidential_burn"
|
||||
| "confidential_mint"
|
||||
| "confidential_burn" => "confidential_mint_burn_extension",
|
||||
_ => name,
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn token_metadata_operations_share_matrix_family() {
|
||||
assert_eq!(matrix_operation_name("update_token_metadata_authority"), "token_metadata");
|
||||
assert_eq!(matrix_operation_name("emit_token_metadata"), "token_metadata");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn machine_readable_matrix_matches_executor_policy() {
|
||||
let matrix = serde_json::from_str::<serde_json::Value>(include_str!(
|
||||
@@ -242,75 +322,7 @@ mod tests {
|
||||
let name = operation_code
|
||||
.strip_prefix("spl.token_2022.")
|
||||
.unwrap_or_else(|| panic!("invalid operation code {operation_code}"));
|
||||
let matrix_name = match name {
|
||||
"initialize_interest_bearing_mint" | "update_interest_bearing_rate" => {
|
||||
"interest_bearing_mint_extension"
|
||||
},
|
||||
"initialize_transfer_fee_config"
|
||||
| "set_transfer_fee"
|
||||
| "transfer_checked_with_fee"
|
||||
| "withdraw_withheld_tokens_from_mint"
|
||||
| "withdraw_withheld_tokens_from_accounts"
|
||||
| "harvest_withheld_tokens_to_mint" => "transfer_fee_extension",
|
||||
"initialize_default_account_state" | "update_default_account_state" => {
|
||||
"default_account_state_extension"
|
||||
},
|
||||
"enable_required_transfer_memos" | "disable_required_transfer_memos" => {
|
||||
"memo_transfer_extension"
|
||||
},
|
||||
"enable_cpi_guard" | "disable_cpi_guard" => "cpi_guard_extension",
|
||||
"initialize_transfer_hook" | "update_transfer_hook" => "transfer_hook_extension",
|
||||
"initialize_metadata_pointer" | "update_metadata_pointer" => {
|
||||
"metadata_pointer_extension"
|
||||
},
|
||||
"initialize_group_pointer" | "update_group_pointer" => "group_pointer_extension",
|
||||
"initialize_group_member_pointer" | "update_group_member_pointer" => {
|
||||
"group_member_pointer_extension"
|
||||
},
|
||||
"initialize_token_metadata"
|
||||
| "update_token_metadata_field"
|
||||
| "remove_token_metadata_key" => "token_metadata",
|
||||
"initialize_token_group" | "update_token_group_max_size" => "token_group",
|
||||
"initialize_token_group_member" => "token_group_member",
|
||||
"initialize_scaled_ui_amount" | "update_scaled_ui_amount_multiplier" => {
|
||||
"scaled_ui_amount_extension"
|
||||
},
|
||||
"initialize_pausable_config" | "pause" | "resume" => "pausable_extension",
|
||||
"initialize_permissioned_burn"
|
||||
| "permissioned_burn"
|
||||
| "permissioned_burn_checked"
|
||||
| "permissioned_confidential_burn" => "permissioned_burn_extension",
|
||||
"initialize_confidential_transfer_mint"
|
||||
| "update_confidential_transfer_mint"
|
||||
| "apply_pending_confidential_balance"
|
||||
| "approve_confidential_transfer_account"
|
||||
| "deposit_confidential_tokens"
|
||||
| "enable_confidential_credits"
|
||||
| "disable_confidential_credits"
|
||||
| "enable_non_confidential_credits"
|
||||
| "disable_non_confidential_credits"
|
||||
| "configure_confidential_transfer_account"
|
||||
| "configure_confidential_transfer_account_with_registry"
|
||||
| "empty_confidential_transfer_account"
|
||||
| "withdraw_confidential_tokens"
|
||||
| "transfer_confidential_tokens"
|
||||
| "transfer_confidential_tokens_with_fee" => "confidential_transfer_extension",
|
||||
"initialize_confidential_transfer_fee_config"
|
||||
| "enable_confidential_transfer_fee_harvest"
|
||||
| "disable_confidential_transfer_fee_harvest"
|
||||
| "harvest_confidential_withheld_tokens_to_mint"
|
||||
| "withdraw_confidential_withheld_tokens_from_mint"
|
||||
| "withdraw_confidential_withheld_tokens_from_accounts" => {
|
||||
"confidential_transfer_fee_extension"
|
||||
},
|
||||
"initialize_confidential_mint_burn_mint"
|
||||
| "rotate_confidential_supply_elgamal_pubkey"
|
||||
| "update_confidential_decryptable_supply"
|
||||
| "apply_pending_confidential_burn"
|
||||
| "confidential_mint"
|
||||
| "confidential_burn" => "confidential_mint_burn_extension",
|
||||
_ => name,
|
||||
};
|
||||
let matrix_name = matrix_operation_name(name);
|
||||
assert!(
|
||||
matrix_names.contains(matrix_name),
|
||||
"matrix is missing supported operation {name}"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/executor/spl/token_2022/intent.rs
|
||||
// version: 26
|
||||
// version: 27
|
||||
|
||||
//! Typed Token-2022 execution intents.
|
||||
|
||||
@@ -138,6 +138,12 @@ pub const EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_FIELD_OPERATION: &str =
|
||||
/// Stable operation code for removing an embedded metadata key.
|
||||
pub const EX_SPL_TOKEN_2022_REMOVE_TOKEN_METADATA_KEY_OPERATION: &str =
|
||||
"spl.token_2022.remove_token_metadata_key";
|
||||
/// Stable operation code for updating or clearing embedded metadata authority.
|
||||
pub const EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_AUTHORITY_OPERATION: &str =
|
||||
"spl.token_2022.update_token_metadata_authority";
|
||||
/// Stable operation code for emitting bounded embedded metadata return data.
|
||||
pub const EX_SPL_TOKEN_2022_EMIT_TOKEN_METADATA_OPERATION: &str =
|
||||
"spl.token_2022.emit_token_metadata";
|
||||
/// Stable operation code for initializing an embedded token group.
|
||||
pub const EX_SPL_TOKEN_2022_INITIALIZE_TOKEN_GROUP_OPERATION: &str =
|
||||
"spl.token_2022.initialize_token_group";
|
||||
@@ -307,6 +313,8 @@ pub const EX_SPL_TOKEN_2022_SUPPORTED_OPERATION_CODES: &[&str] = &[
|
||||
EX_SPL_TOKEN_2022_INITIALIZE_TOKEN_METADATA_OPERATION,
|
||||
EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_FIELD_OPERATION,
|
||||
EX_SPL_TOKEN_2022_REMOVE_TOKEN_METADATA_KEY_OPERATION,
|
||||
EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_AUTHORITY_OPERATION,
|
||||
EX_SPL_TOKEN_2022_EMIT_TOKEN_METADATA_OPERATION,
|
||||
EX_SPL_TOKEN_2022_INITIALIZE_TOKEN_GROUP_OPERATION,
|
||||
EX_SPL_TOKEN_2022_UPDATE_TOKEN_GROUP_MAX_SIZE_OPERATION,
|
||||
EX_SPL_TOKEN_2022_INITIALIZE_TOKEN_GROUP_MEMBER_OPERATION,
|
||||
@@ -919,6 +927,24 @@ pub enum ExSplTokenSingleOperation {
|
||||
/// Whether a missing key is accepted.
|
||||
idempotent: bool,
|
||||
},
|
||||
/// Update or permanently clear embedded metadata authority.
|
||||
UpdateTokenMetadataAuthority {
|
||||
/// Metadata account.
|
||||
metadata: crate::MdPubkey,
|
||||
/// Current update authority signer.
|
||||
current_authority: crate::MdPubkey,
|
||||
/// New authority, or `None` to make metadata immutable.
|
||||
new_authority: std::option::Option<crate::MdPubkey>,
|
||||
},
|
||||
/// Emit all or one bounded range of embedded metadata through return data.
|
||||
EmitTokenMetadata {
|
||||
/// Metadata account.
|
||||
metadata: crate::MdPubkey,
|
||||
/// Optional inclusive byte-range start.
|
||||
start: std::option::Option<u64>,
|
||||
/// Optional exclusive byte-range end.
|
||||
end: std::option::Option<u64>,
|
||||
},
|
||||
/// Initialize a Token Group entry.
|
||||
InitializeTokenGroup {
|
||||
/// Group state account, normally the group mint.
|
||||
@@ -1454,6 +1480,10 @@ impl crate::ExSplTokenSingleOperation {
|
||||
Self::InitializeTokenMetadata { .. } => crate::EX_SPL_TOKEN_2022_INITIALIZE_TOKEN_METADATA_OPERATION,
|
||||
Self::UpdateTokenMetadataField { .. } => crate::EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_FIELD_OPERATION,
|
||||
Self::RemoveTokenMetadataKey { .. } => crate::EX_SPL_TOKEN_2022_REMOVE_TOKEN_METADATA_KEY_OPERATION,
|
||||
Self::UpdateTokenMetadataAuthority { .. } => {
|
||||
crate::EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_AUTHORITY_OPERATION
|
||||
},
|
||||
Self::EmitTokenMetadata { .. } => crate::EX_SPL_TOKEN_2022_EMIT_TOKEN_METADATA_OPERATION,
|
||||
Self::InitializeTokenGroup { .. } => crate::EX_SPL_TOKEN_2022_INITIALIZE_TOKEN_GROUP_OPERATION,
|
||||
Self::UpdateTokenGroupMaxSize { .. } => crate::EX_SPL_TOKEN_2022_UPDATE_TOKEN_GROUP_MAX_SIZE_OPERATION,
|
||||
Self::InitializeTokenGroupMember { .. } => {
|
||||
@@ -1566,6 +1596,7 @@ impl crate::ExSplTokenSingleOperation {
|
||||
return !matches!(
|
||||
self,
|
||||
Self::GetAccountDataSize { .. }
|
||||
| Self::EmitTokenMetadata { .. }
|
||||
| Self::InitializeImmutableOwner { .. }
|
||||
| Self::AmountToUiAmount { .. }
|
||||
| Self::UiAmountToAmount { .. }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/lib.rs
|
||||
// version: 37
|
||||
// version: 38
|
||||
|
||||
//! Consolidated decoder, executor, materializer and shared model library.
|
||||
#![warn(missing_docs)]
|
||||
@@ -401,6 +401,8 @@ pub use self::decoder::decoder_metadata_solana_program_metadata_decode_metadata_
|
||||
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;
|
||||
/// Parses one exact Token Metadata interface value.
|
||||
pub use self::decoder::decoder_spl_token_2022_parse_token_metadata_value;
|
||||
/// Stable Solana Program Metadata `Allocate` operation code.
|
||||
pub use self::executor::EX_METADATA_SPM_ALLOCATE_OPERATION;
|
||||
/// Stable Solana Program Metadata `Close` operation code.
|
||||
@@ -791,6 +793,8 @@ pub use self::executor::EX_SPL_TOKEN_2022_DISABLE_REQUIRED_TRANSFER_MEMOS_OPERAT
|
||||
pub use self::executor::EX_SPL_TOKEN_2022_ELGAMAL_CIPHERTEXT_BYTES;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_ELGAMAL_PUBKEY_BYTES`.
|
||||
pub use self::executor::EX_SPL_TOKEN_2022_ELGAMAL_PUBKEY_BYTES;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_EMIT_TOKEN_METADATA_OPERATION`.
|
||||
pub use self::executor::EX_SPL_TOKEN_2022_EMIT_TOKEN_METADATA_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_EMPTY_CONFIDENTIAL_TRANSFER_ACCOUNT_OPERATION`.
|
||||
pub use self::executor::EX_SPL_TOKEN_2022_EMPTY_CONFIDENTIAL_TRANSFER_ACCOUNT_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_ENABLE_CONFIDENTIAL_CREDITS_OPERATION`.
|
||||
@@ -921,6 +925,8 @@ pub use self::executor::EX_SPL_TOKEN_2022_UPDATE_METADATA_POINTER_OPERATION;
|
||||
pub use self::executor::EX_SPL_TOKEN_2022_UPDATE_SCALED_UI_AMOUNT_MULTIPLIER_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_UPDATE_TOKEN_GROUP_MAX_SIZE_OPERATION`.
|
||||
pub use self::executor::EX_SPL_TOKEN_2022_UPDATE_TOKEN_GROUP_MAX_SIZE_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_AUTHORITY_OPERATION`.
|
||||
pub use self::executor::EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_AUTHORITY_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_FIELD_OPERATION`.
|
||||
pub use self::executor::EX_SPL_TOKEN_2022_UPDATE_TOKEN_METADATA_FIELD_OPERATION;
|
||||
/// Exposes `EX_SPL_TOKEN_2022_UPDATE_TRANSFER_HOOK_OPERATION`.
|
||||
|
||||
Reference in New Issue
Block a user