v0.1.0-pre.017
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/executor.rs
|
||||
// version: 4
|
||||
// version: 5
|
||||
|
||||
//! Consolidated executor modules.
|
||||
|
||||
@@ -493,6 +493,14 @@ pub use self::solana::ExSolanaCoreVoteLockout;
|
||||
pub use self::solana::ExSolanaCoreZkElGamalContextState;
|
||||
/// Exposes the official ZK ElGamal proof kinds.
|
||||
pub use self::solana::ExSolanaCoreZkElGamalProofType;
|
||||
/// Exposes the idempotent ATA creation operation code.
|
||||
pub use self::spl::EX_SPL_ATA_CREATE_IDEMPOTENT_OPERATION;
|
||||
/// Exposes the strict ATA creation operation code.
|
||||
pub use self::spl::EX_SPL_ATA_CREATE_OPERATION;
|
||||
/// Exposes the nested ATA recovery operation code.
|
||||
pub use self::spl::EX_SPL_ATA_RECOVER_NESTED_OPERATION;
|
||||
/// Exposes every supported ATA operation code.
|
||||
pub use self::spl::EX_SPL_ATA_SUPPORTED_OPERATION_CODES;
|
||||
/// Exposes the stable SPL Memo add-memo operation code.
|
||||
pub use self::spl::EX_SPL_MEMO_ADD_MEMO_OPERATION;
|
||||
/// Exposes the SPL Memo payload bound.
|
||||
@@ -501,8 +509,14 @@ pub use self::spl::EX_SPL_MEMO_MAX_MESSAGE_BYTES;
|
||||
pub use self::spl::EX_SPL_MEMO_MAX_SIGNERS;
|
||||
/// Exposes the reserved `spl/account_compression` executor.
|
||||
pub use self::spl::ExSplAccountCompressionExecutor;
|
||||
/// Exposes the reserved `spl/associated_token_account` executor.
|
||||
/// Exposes the typed SPL ATA execution intent.
|
||||
pub use self::spl::ExSplAssociatedTokenAccountExecutionIntent;
|
||||
/// Exposes the SPL ATA executor.
|
||||
pub use self::spl::ExSplAssociatedTokenAccountExecutor;
|
||||
/// Exposes one typed SPL ATA operation.
|
||||
pub use self::spl::ExSplAssociatedTokenAccountOperation;
|
||||
/// Exposes the exact Token Program used by ATA derivation.
|
||||
pub use self::spl::ExSplAssociatedTokenProgram;
|
||||
/// Exposes the reserved `spl/elgamal_registry` executor.
|
||||
pub use self::spl::ExSplElgamalRegistryExecutor;
|
||||
/// Exposes the typed SPL Memo execution intent.
|
||||
@@ -598,8 +612,12 @@ pub(crate) use self::solana::executor_solana_core_validate_seeded_address;
|
||||
pub(crate) use self::solana::executor_solana_core_vote_build_prepared_plan;
|
||||
/// Crate-root access to `build_prepared_plan` from `zk_elgamal`.
|
||||
pub(crate) use self::solana::executor_solana_core_zk_elgamal_build_prepared_plan;
|
||||
/// Canonical SPL ATA tracing target.
|
||||
pub(crate) use self::spl::EX_SPL_ATA_TRACING_TARGET;
|
||||
/// Canonical SPL Memo tracing target.
|
||||
pub(crate) use self::spl::EX_SPL_MEMO_TRACING_TARGET;
|
||||
/// Internal SPL ATA plan builder.
|
||||
pub(crate) use self::spl::executor_spl_ata_build_prepared_plan;
|
||||
/// Internal SPL Memo plan builder.
|
||||
pub(crate) use self::spl::executor_spl_memo_build_prepared_plan;
|
||||
|
||||
@@ -607,7 +625,7 @@ pub(crate) use self::spl::executor_spl_memo_build_prepared_plan;
|
||||
mod reserved_executor_tests {
|
||||
#[test]
|
||||
fn every_reserved_executor_is_registered_and_builds_only_an_empty_plan() {
|
||||
let executors: [&dyn crate::ExApiInstructionExecutor; 102] = [
|
||||
let executors: [&dyn crate::ExApiInstructionExecutor; 101] = [
|
||||
&crate::ExAdapterSaberDecimalWrapperExecutor,
|
||||
&crate::ExAdminJupiterLockExecutor,
|
||||
&crate::ExAdminPumpFeesExecutor,
|
||||
@@ -686,7 +704,6 @@ mod reserved_executor_tests {
|
||||
&crate::ExRouterOkxLabsV2Executor,
|
||||
&crate::ExRwaOndoGlobalMarketsExecutor,
|
||||
&crate::ExSplAccountCompressionExecutor,
|
||||
&crate::ExSplAssociatedTokenAccountExecutor,
|
||||
&crate::ExSplElgamalRegistryExecutor,
|
||||
&crate::ExSplNoopExecutor,
|
||||
&crate::ExSplSinglePoolExecutor,
|
||||
@@ -711,7 +728,7 @@ mod reserved_executor_tests {
|
||||
&crate::ExWalletJupiterApeproSmartWalletExecutor,
|
||||
&crate::ExWeightedSwapStabbleExecutor,
|
||||
];
|
||||
assert_eq!(executors.len(), 103);
|
||||
assert_eq!(executors.len(), 101);
|
||||
for executor in executors {
|
||||
assert!(!executor.program_ids().is_empty());
|
||||
for program_id in executor.program_ids() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/executor/api/execution.rs
|
||||
// version: 7
|
||||
// version: 8
|
||||
|
||||
//! Typed execution plans, policies and result contracts.
|
||||
|
||||
@@ -10,7 +10,7 @@ use ts_rs::TS; // rust-rules: derive-import
|
||||
#[serde(tag = "status", rename_all = "snake_case")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/execution/ExecutionCapability.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/execution/ExecutionCapability.ts"
|
||||
)]
|
||||
pub enum ExApiExecutionCapability {
|
||||
/// The operation is implemented by the executor.
|
||||
@@ -55,7 +55,7 @@ impl crate::ExApiExecutionCapability {
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/execution/ExecutionCluster.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/execution/ExecutionCluster.ts"
|
||||
)]
|
||||
pub enum ExApiExecutionCluster {
|
||||
/// Local validator cluster.
|
||||
@@ -104,7 +104,7 @@ impl<'de> serde::Deserialize<'de> for crate::ExApiExecutionCluster {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/execution/ExecutionClusterPolicy.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/execution/ExecutionClusterPolicy.ts"
|
||||
)]
|
||||
pub struct ExApiExecutionClusterPolicy {
|
||||
/// Cluster that the RPC endpoint must report.
|
||||
@@ -130,7 +130,7 @@ impl std::default::Default for crate::ExApiExecutionClusterPolicy {
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/execution/ExecutionSimulationPolicy.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/execution/ExecutionSimulationPolicy.ts"
|
||||
)]
|
||||
pub enum ExApiExecutionSimulationPolicy {
|
||||
/// Simulation must succeed before signing or sending.
|
||||
@@ -144,7 +144,7 @@ pub enum ExApiExecutionSimulationPolicy {
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/execution/ExecutionBlockhashKind.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/execution/ExecutionBlockhashKind.ts"
|
||||
)]
|
||||
pub enum ExApiExecutionBlockhashKind {
|
||||
/// Fetch a recent blockhash and enforce a bounded age.
|
||||
@@ -157,7 +157,7 @@ pub enum ExApiExecutionBlockhashKind {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/execution/ExecutionBlockhashPolicy.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/execution/ExecutionBlockhashPolicy.ts"
|
||||
)]
|
||||
pub struct ExApiExecutionBlockhashPolicy {
|
||||
/// Selected blockhash source.
|
||||
@@ -185,7 +185,7 @@ impl std::default::Default for crate::ExApiExecutionBlockhashPolicy {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/execution/ExecutionCostLimit.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/execution/ExecutionCostLimit.ts"
|
||||
)]
|
||||
pub struct ExApiExecutionCostLimit {
|
||||
/// Maximum lamports that operation instructions may transfer or lock.
|
||||
@@ -210,7 +210,7 @@ impl std::default::Default for crate::ExApiExecutionCostLimit {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/execution/PostExecutionValidationPolicy.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/execution/PostExecutionValidationPolicy.ts"
|
||||
)]
|
||||
pub struct ExApiPostExecutionValidationPolicy {
|
||||
/// Whether the sent signature must be inserted into canonical storage.
|
||||
@@ -238,7 +238,7 @@ impl std::default::Default for crate::ExApiPostExecutionValidationPolicy {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/execution/ExecutionPolicy.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/execution/ExecutionPolicy.ts"
|
||||
)]
|
||||
pub struct ExApiExecutionPolicy {
|
||||
/// Cluster restrictions.
|
||||
@@ -275,7 +275,7 @@ impl std::default::Default for crate::ExApiExecutionPolicy {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/execution/PlannedAccount.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/execution/PlannedAccount.ts"
|
||||
)]
|
||||
pub struct ExApiPlannedAccount {
|
||||
/// Account public key.
|
||||
@@ -290,7 +290,7 @@ pub struct ExApiPlannedAccount {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/execution/PlannedInstruction.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/execution/PlannedInstruction.ts"
|
||||
)]
|
||||
pub struct ExApiPlannedInstruction {
|
||||
/// Target program id.
|
||||
@@ -307,7 +307,7 @@ pub struct ExApiPlannedInstruction {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/execution/RequiredSigner.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/execution/RequiredSigner.ts"
|
||||
)]
|
||||
pub struct ExApiRequiredSigner {
|
||||
/// Signer public key.
|
||||
@@ -320,7 +320,7 @@ pub struct ExApiRequiredSigner {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/execution/PreparedExecutionPlan.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/execution/PreparedExecutionPlan.ts"
|
||||
)]
|
||||
pub struct ExApiPreparedExecutionPlan {
|
||||
/// Stable executor crate name.
|
||||
@@ -349,7 +349,7 @@ pub struct ExApiPreparedExecutionPlan {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/execution/ExecutionSimulationResult.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/execution/ExecutionSimulationResult.ts"
|
||||
)]
|
||||
pub struct ExApiExecutionSimulationResult {
|
||||
/// Whether an RPC simulation call was actually performed.
|
||||
@@ -386,7 +386,7 @@ pub struct ExApiExecutionSimulationResult {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/execution/ExecutionSendResult.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/execution/ExecutionSendResult.ts"
|
||||
)]
|
||||
pub struct ExApiExecutionSendResult {
|
||||
/// Cluster used for submission.
|
||||
@@ -402,7 +402,7 @@ pub struct ExApiExecutionSendResult {
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/execution/ExecutionConfirmationStatus.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/execution/ExecutionConfirmationStatus.ts"
|
||||
)]
|
||||
pub enum ExApiExecutionConfirmationStatus {
|
||||
/// The transaction was observed at processed commitment.
|
||||
@@ -423,7 +423,7 @@ pub enum ExApiExecutionConfirmationStatus {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/execution/ExecutionConfirmationResult.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/execution/ExecutionConfirmationResult.ts"
|
||||
)]
|
||||
pub struct ExApiExecutionConfirmationResult {
|
||||
/// Cluster queried for confirmation.
|
||||
@@ -446,7 +446,7 @@ pub struct ExApiExecutionConfirmationResult {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/execution/PostExecutionDiagnostic.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/execution/PostExecutionDiagnostic.ts"
|
||||
)]
|
||||
pub struct ExApiPostExecutionDiagnostic {
|
||||
/// Executed transaction signature.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/executor/api/executor.rs
|
||||
// version: 3
|
||||
// version: 4
|
||||
|
||||
//! Shared execution contract and neutral request models.
|
||||
|
||||
@@ -9,7 +9,7 @@ use ts_rs::TS; // rust-rules: derive-import
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/executor/ExecutionSupport.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/executor/ExecutionSupport.ts"
|
||||
)]
|
||||
pub enum ExApiExecutionSupport {
|
||||
/// The executor cannot handle the request.
|
||||
@@ -24,7 +24,7 @@ pub enum ExApiExecutionSupport {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/executor/ExecutionRequest.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/executor/ExecutionRequest.ts"
|
||||
)]
|
||||
pub struct ExApiExecutionRequest {
|
||||
/// Target program id.
|
||||
@@ -39,7 +39,7 @@ pub struct ExApiExecutionRequest {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_execution_api/executor/ExecutionPlan.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/api/executor/ExecutionPlan.ts"
|
||||
)]
|
||||
pub struct ExApiExecutionPlan {
|
||||
/// Stable executor crate name.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/executor/safety/evaluation.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
//! Safety checks applied before simulation, signing or sending.
|
||||
|
||||
@@ -10,7 +10,7 @@ use ts_rs::TS; // rust-rules: derive-import
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/safety/ExSafetyDecision.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/safety/evaluation/ExSafetyDecision.ts"
|
||||
)]
|
||||
pub enum ExSafetyDecision {
|
||||
/// The plan is not allowed to continue.
|
||||
@@ -25,7 +25,7 @@ pub enum ExSafetyDecision {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/safety/ExSafetyViolation.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/safety/evaluation/ExSafetyViolation.ts"
|
||||
)]
|
||||
pub struct ExSafetyViolation {
|
||||
/// Stable violation code.
|
||||
@@ -38,7 +38,7 @@ pub struct ExSafetyViolation {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/safety/ExSafetyEvaluation.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/safety/evaluation/ExSafetyEvaluation.ts"
|
||||
)]
|
||||
pub struct ExSafetyEvaluation {
|
||||
/// Aggregate decision.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/executor/spl.rs
|
||||
// version: 3
|
||||
// version: 4
|
||||
|
||||
//! `spl` executor family.
|
||||
|
||||
@@ -14,8 +14,22 @@ mod token;
|
||||
mod token2022;
|
||||
/// Exposes the reserved `spl/account_compression` executor.
|
||||
pub use self::account_compression::ExSplAccountCompressionExecutor;
|
||||
/// Exposes the reserved `spl/associated_token_account` executor.
|
||||
/// Exposes the idempotent ATA creation operation code.
|
||||
pub use self::associated_token_account::EX_SPL_ATA_CREATE_IDEMPOTENT_OPERATION;
|
||||
/// Exposes the strict ATA creation operation code.
|
||||
pub use self::associated_token_account::EX_SPL_ATA_CREATE_OPERATION;
|
||||
/// Exposes the nested ATA recovery operation code.
|
||||
pub use self::associated_token_account::EX_SPL_ATA_RECOVER_NESTED_OPERATION;
|
||||
/// Exposes every supported ATA operation code.
|
||||
pub use self::associated_token_account::EX_SPL_ATA_SUPPORTED_OPERATION_CODES;
|
||||
/// Exposes the typed SPL ATA execution intent.
|
||||
pub use self::associated_token_account::ExSplAssociatedTokenAccountExecutionIntent;
|
||||
/// Exposes the SPL ATA executor.
|
||||
pub use self::associated_token_account::ExSplAssociatedTokenAccountExecutor;
|
||||
/// Exposes one typed SPL ATA operation.
|
||||
pub use self::associated_token_account::ExSplAssociatedTokenAccountOperation;
|
||||
/// Exposes the exact Token Program used by ATA derivation.
|
||||
pub use self::associated_token_account::ExSplAssociatedTokenProgram;
|
||||
/// Exposes the reserved `spl/elgamal_registry` executor.
|
||||
pub use self::elgamal_registry::ExSplElgamalRegistryExecutor;
|
||||
/// Exposes the stable SPL Memo add-memo operation code.
|
||||
@@ -45,6 +59,10 @@ pub use self::token::ExSplTokenExecutor;
|
||||
/// Exposes the reserved `spl/token2022` executor.
|
||||
pub use self::token2022::ExSplToken2022Executor;
|
||||
|
||||
/// Canonical SPL ATA tracing target.
|
||||
pub(crate) use self::associated_token_account::EX_SPL_ATA_TRACING_TARGET;
|
||||
/// Internal SPL ATA plan builder.
|
||||
pub(crate) use self::associated_token_account::executor_spl_ata_build_prepared_plan;
|
||||
/// Canonical SPL Memo tracing target.
|
||||
pub(crate) use self::memo::EX_SPL_MEMO_TRACING_TARGET;
|
||||
/// Internal SPL Memo plan builder.
|
||||
|
||||
@@ -1,49 +1,31 @@
|
||||
// file: kb-lib/src/executor/spl/associated_token_account.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
//! Reserved executor for `spl_associated_token_account`.
|
||||
//! Safe typed executor for SPL Associated Token Account.
|
||||
|
||||
/// Reserved executor for the `spl_associated_token_account` program surface.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct ExSplAssociatedTokenAccountExecutor;
|
||||
mod builder;
|
||||
mod constants;
|
||||
mod executor;
|
||||
mod intent;
|
||||
|
||||
impl crate::ExApiInstructionExecutor for crate::ExSplAssociatedTokenAccountExecutor {
|
||||
fn executor_name(&self) -> &'static str {
|
||||
return "kb_executor_spl_associated_token_account";
|
||||
}
|
||||
/// Exposes the SPL ATA executor.
|
||||
pub use self::executor::ExSplAssociatedTokenAccountExecutor;
|
||||
/// Exposes the idempotent ATA creation operation code.
|
||||
pub use self::intent::EX_SPL_ATA_CREATE_IDEMPOTENT_OPERATION;
|
||||
/// Exposes the strict ATA creation operation code.
|
||||
pub use self::intent::EX_SPL_ATA_CREATE_OPERATION;
|
||||
/// Exposes the nested ATA recovery operation code.
|
||||
pub use self::intent::EX_SPL_ATA_RECOVER_NESTED_OPERATION;
|
||||
/// Exposes every currently supported ATA operation code.
|
||||
pub use self::intent::EX_SPL_ATA_SUPPORTED_OPERATION_CODES;
|
||||
/// Exposes the typed SPL ATA execution intent.
|
||||
pub use self::intent::ExSplAssociatedTokenAccountExecutionIntent;
|
||||
/// Exposes one typed SPL ATA operation.
|
||||
pub use self::intent::ExSplAssociatedTokenAccountOperation;
|
||||
/// Exposes the exact Token Program used by ATA derivation.
|
||||
pub use self::intent::ExSplAssociatedTokenProgram;
|
||||
|
||||
fn executor_version(&self) -> &'static str {
|
||||
return env!("CARGO_PKG_VERSION");
|
||||
}
|
||||
|
||||
fn program_ids(&self) -> &'static [&'static str] {
|
||||
return &[kb_program_ids::ASSOCIATED_TOKEN_PROGRAM_ID];
|
||||
}
|
||||
|
||||
fn supports_request(
|
||||
&self,
|
||||
request: &crate::ExApiExecutionRequest,
|
||||
) -> crate::ExApiExecutionSupport {
|
||||
if crate::ExApiInstructionExecutor::handles_program_id(self, &request.program_id) {
|
||||
return crate::ExApiExecutionSupport::Maybe;
|
||||
}
|
||||
return crate::ExApiExecutionSupport::No;
|
||||
}
|
||||
|
||||
fn build_plan(
|
||||
&self,
|
||||
_request: &crate::ExApiExecutionRequest,
|
||||
) -> kb_core::Result<crate::ExApiExecutionPlan> {
|
||||
let payload_json = match crate::executor_api_serialize_payload_json(
|
||||
&serde_json::json!({"status":"reserved_executor","surface":"spl_associated_token_account"}),
|
||||
) {
|
||||
std::result::Result::Ok(serialized) => serialized,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
return std::result::Result::Ok(crate::ExApiExecutionPlan {
|
||||
executor_name: "kb_executor_spl_associated_token_account".to_string(),
|
||||
instruction_count: 0,
|
||||
payload_json,
|
||||
});
|
||||
}
|
||||
}
|
||||
/// Internal SPL ATA plan builder.
|
||||
pub(crate) use self::builder::executor_spl_ata_build_prepared_plan;
|
||||
/// Canonical tracing target for SPL ATA execution.
|
||||
pub(crate) use self::constants::EX_SPL_ATA_TRACING_TARGET;
|
||||
|
||||
489
kb-lib/src/executor/spl/associated_token_account/builder.rs
Normal file
489
kb-lib/src/executor/spl/associated_token_account/builder.rs
Normal file
@@ -0,0 +1,489 @@
|
||||
// file: kb-lib/src/executor/spl/associated_token_account/builder.rs
|
||||
// version: 4
|
||||
|
||||
//! Official ATA builders and conservative simulation-first plan validation.
|
||||
|
||||
macro_rules! parse_key {
|
||||
($value:expr, $field:expr) => {
|
||||
match $value.0.parse() {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_spl_ata_pubkey_invalid",
|
||||
format!("invalid ATA {} public key: {error}", $field),
|
||||
));
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) fn executor_spl_ata_build_prepared_plan(
|
||||
intent: &crate::ExSplAssociatedTokenAccountExecutionIntent,
|
||||
) -> kb_core::Result<crate::ExApiPreparedExecutionPlan> {
|
||||
if intent.intent_id.trim().is_empty() {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_spl_ata_intent_id_empty",
|
||||
"ATA execution intent id must not be empty",
|
||||
));
|
||||
}
|
||||
match validate_policy(intent) {
|
||||
std::result::Result::Ok(()) => {},
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
}
|
||||
let fee_payer = parse_key!(&intent.fee_payer, "fee_payer");
|
||||
let token_program_text = intent.operation.token_program().program_id();
|
||||
let instruction = match &intent.operation {
|
||||
crate::ExSplAssociatedTokenAccountOperation::Create {
|
||||
wallet_owner,
|
||||
mint,
|
||||
token_program: _,
|
||||
} => {
|
||||
let wallet_owner = parse_key!(wallet_owner, "wallet_owner");
|
||||
let mint = parse_key!(mint, "mint");
|
||||
let token_program: solana_pubkey::Pubkey = match token_program_text.parse() {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_spl_ata_token_program_invalid",
|
||||
error.to_string(),
|
||||
));
|
||||
},
|
||||
};
|
||||
spl_associated_token_account_interface::instruction::create_associated_token_account(
|
||||
&fee_payer,
|
||||
&wallet_owner,
|
||||
&mint,
|
||||
&token_program,
|
||||
)
|
||||
},
|
||||
crate::ExSplAssociatedTokenAccountOperation::CreateIdempotent {
|
||||
wallet_owner,
|
||||
mint,
|
||||
token_program: _,
|
||||
} => {
|
||||
let wallet_owner = parse_key!(wallet_owner, "wallet_owner");
|
||||
let mint = parse_key!(mint, "mint");
|
||||
let token_program: solana_pubkey::Pubkey = match token_program_text.parse() {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_spl_ata_token_program_invalid",
|
||||
error.to_string(),
|
||||
));
|
||||
},
|
||||
};
|
||||
spl_associated_token_account_interface::instruction::create_associated_token_account_idempotent(
|
||||
&fee_payer,
|
||||
&wallet_owner,
|
||||
&mint,
|
||||
&token_program,
|
||||
)
|
||||
},
|
||||
crate::ExSplAssociatedTokenAccountOperation::RecoverNested {
|
||||
wallet_owner,
|
||||
owner_mint,
|
||||
nested_mint,
|
||||
token_program: _,
|
||||
} => {
|
||||
let wallet_owner = parse_key!(wallet_owner, "wallet_owner");
|
||||
let owner_mint = parse_key!(owner_mint, "owner_mint");
|
||||
let nested_mint = parse_key!(nested_mint, "nested_mint");
|
||||
let token_program: solana_pubkey::Pubkey = match token_program_text.parse() {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_spl_ata_token_program_invalid",
|
||||
error.to_string(),
|
||||
));
|
||||
},
|
||||
};
|
||||
spl_associated_token_account_interface::instruction::recover_nested(
|
||||
&wallet_owner,
|
||||
&owner_mint,
|
||||
&nested_mint,
|
||||
&token_program,
|
||||
)
|
||||
},
|
||||
};
|
||||
let planned_instruction = planned_instruction(intent.operation.operation_code(), &instruction);
|
||||
let required_signers = required_signers(&intent.fee_payer, &planned_instruction.accounts);
|
||||
tracing::debug!(
|
||||
target: crate::EX_SPL_ATA_TRACING_TARGET,
|
||||
action = "build_prepared_plan",
|
||||
intent_id = %intent.intent_id,
|
||||
operation_code = intent.operation.operation_code(),
|
||||
token_program_id = token_program_text,
|
||||
account_occurrence_count = planned_instruction.accounts.len(),
|
||||
required_signer_count = required_signers.len(),
|
||||
max_rent_lamports = intent.max_rent_lamports,
|
||||
dry_run = intent.policy.dry_run,
|
||||
"built SPL Associated Token Account execution plan"
|
||||
);
|
||||
return std::result::Result::Ok(crate::ExApiPreparedExecutionPlan {
|
||||
executor_name: "kb_executor_spl_associated_token_account".to_string(),
|
||||
executor_version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
intent_id: intent.intent_id.clone(),
|
||||
operation_code: intent.operation.operation_code().to_string(),
|
||||
fee_payer: crate::MdPubkey(fee_payer.to_string()),
|
||||
instructions: std::vec![planned_instruction],
|
||||
required_signers,
|
||||
policy: intent.policy.clone(),
|
||||
requested_spend_lamports: intent.max_rent_lamports,
|
||||
requested_compute_unit_price_micro_lamports: std::option::Option::None,
|
||||
});
|
||||
}
|
||||
|
||||
fn validate_policy(
|
||||
intent: &crate::ExSplAssociatedTokenAccountExecutionIntent,
|
||||
) -> kb_core::Result<()> {
|
||||
if intent.policy.simulation != crate::ExApiExecutionSimulationPolicy::Required {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_spl_ata_simulation_required",
|
||||
"ATA execution requires simulation before signing or sending",
|
||||
));
|
||||
}
|
||||
if intent.operation.is_creation() && intent.max_rent_lamports == 0 {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_spl_ata_rent_limit_missing",
|
||||
"ATA creation requires a positive rent spending ceiling",
|
||||
));
|
||||
}
|
||||
if !intent.operation.is_creation() && intent.max_rent_lamports != 0 {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_spl_ata_recovery_rent_must_be_zero",
|
||||
"RecoverNested must declare zero rent spending",
|
||||
));
|
||||
}
|
||||
if intent.policy.cost_limit.max_spend_lamports
|
||||
!= std::option::Option::Some(intent.max_rent_lamports)
|
||||
{
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_spl_ata_spend_limit_mismatch",
|
||||
"ATA policy max spend must equal the declared maximum rent lamports",
|
||||
));
|
||||
}
|
||||
match intent.policy.cost_limit.max_fee_lamports {
|
||||
std::option::Option::Some(value) if value > 0 => {},
|
||||
std::option::Option::Some(_) | std::option::Option::None => {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_spl_ata_fee_limit_missing",
|
||||
"ATA execution requires a positive transaction fee ceiling",
|
||||
));
|
||||
},
|
||||
}
|
||||
let validation = &intent.policy.post_execution_validation;
|
||||
if !validation.canonical_insert_required
|
||||
|| !validation.core_extraction_required
|
||||
|| !validation.decode_replay_required
|
||||
|| !validation.materialization_required
|
||||
{
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_spl_ata_post_validation_required",
|
||||
"ATA execution requires canonical insertion, core extraction, decode replay and materialization validation",
|
||||
));
|
||||
}
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
|
||||
fn planned_instruction(
|
||||
operation_code: &str,
|
||||
instruction: &solana_instruction::Instruction,
|
||||
) -> crate::ExApiPlannedInstruction {
|
||||
return crate::ExApiPlannedInstruction {
|
||||
program_id: crate::MdProgramId(instruction.program_id.to_string()),
|
||||
operation_code: operation_code.to_string(),
|
||||
accounts: instruction
|
||||
.accounts
|
||||
.iter()
|
||||
.map(|account| {
|
||||
return crate::ExApiPlannedAccount {
|
||||
pubkey: crate::MdPubkey(account.pubkey.to_string()),
|
||||
is_signer: account.is_signer,
|
||||
is_writable: account.is_writable,
|
||||
};
|
||||
})
|
||||
.collect(),
|
||||
data: instruction.data.clone(),
|
||||
};
|
||||
}
|
||||
|
||||
fn required_signers(
|
||||
fee_payer: &crate::MdPubkey,
|
||||
accounts: &[crate::ExApiPlannedAccount],
|
||||
) -> std::vec::Vec<crate::ExApiRequiredSigner> {
|
||||
let mut required = std::vec![crate::ExApiRequiredSigner {
|
||||
pubkey: fee_payer.clone(),
|
||||
role: "fee_payer".to_string(),
|
||||
}];
|
||||
for account in accounts.iter().filter(|account| return account.is_signer) {
|
||||
if required.iter().any(|candidate| return candidate.pubkey == account.pubkey) {
|
||||
continue;
|
||||
}
|
||||
required.push(crate::ExApiRequiredSigner {
|
||||
pubkey: account.pubkey.clone(),
|
||||
role: "wallet_owner".to_string(),
|
||||
});
|
||||
}
|
||||
return required;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
fn pubkey(value: &str) -> crate::MdPubkey {
|
||||
return crate::MdPubkey(value.to_string());
|
||||
}
|
||||
|
||||
fn intent(
|
||||
operation: crate::ExSplAssociatedTokenAccountOperation,
|
||||
max_rent_lamports: u64,
|
||||
) -> crate::ExSplAssociatedTokenAccountExecutionIntent {
|
||||
let fee_payer = pubkey(kb_program_ids::SYSTEM_PROGRAM_ID);
|
||||
let wallet_owner = match &operation {
|
||||
crate::ExSplAssociatedTokenAccountOperation::Create { wallet_owner, .. }
|
||||
| crate::ExSplAssociatedTokenAccountOperation::CreateIdempotent {
|
||||
wallet_owner, ..
|
||||
}
|
||||
| crate::ExSplAssociatedTokenAccountOperation::RecoverNested { wallet_owner, .. } => {
|
||||
wallet_owner.clone()
|
||||
},
|
||||
};
|
||||
let mut authorized_signers = std::vec![fee_payer.clone()];
|
||||
if !authorized_signers.contains(&wallet_owner) {
|
||||
authorized_signers.push(wallet_owner);
|
||||
}
|
||||
return crate::ExSplAssociatedTokenAccountExecutionIntent {
|
||||
intent_id: "ata-intent-1".to_string(),
|
||||
fee_payer,
|
||||
max_rent_lamports,
|
||||
policy: crate::ExApiExecutionPolicy {
|
||||
simulation: crate::ExApiExecutionSimulationPolicy::Required,
|
||||
cost_limit: crate::ExApiExecutionCostLimit {
|
||||
max_spend_lamports: std::option::Option::Some(max_rent_lamports),
|
||||
max_fee_lamports: std::option::Option::Some(10_000),
|
||||
max_compute_unit_price_micro_lamports: std::option::Option::None,
|
||||
},
|
||||
authorized_signers,
|
||||
dry_run: true,
|
||||
post_execution_validation: crate::ExApiPostExecutionValidationPolicy {
|
||||
canonical_insert_required: true,
|
||||
core_extraction_required: true,
|
||||
decode_replay_required: true,
|
||||
materialization_required: true,
|
||||
},
|
||||
..crate::ExApiExecutionPolicy::default()
|
||||
},
|
||||
operation,
|
||||
};
|
||||
}
|
||||
|
||||
fn official_instruction(
|
||||
intent: &crate::ExSplAssociatedTokenAccountExecutionIntent,
|
||||
) -> solana_instruction::Instruction {
|
||||
let fee_payer = intent
|
||||
.fee_payer
|
||||
.0
|
||||
.parse()
|
||||
.unwrap_or_else(|error| panic!("invalid fee payer fixture: {error}"));
|
||||
let token_program = intent
|
||||
.operation
|
||||
.token_program()
|
||||
.program_id()
|
||||
.parse()
|
||||
.unwrap_or_else(|error| panic!("invalid Token Program fixture: {error}"));
|
||||
return match &intent.operation {
|
||||
crate::ExSplAssociatedTokenAccountOperation::Create {
|
||||
wallet_owner,
|
||||
mint,
|
||||
token_program: _,
|
||||
} => {
|
||||
let wallet_owner = wallet_owner
|
||||
.0
|
||||
.parse()
|
||||
.unwrap_or_else(|error| panic!("invalid wallet fixture: {error}"));
|
||||
let mint =
|
||||
mint.0.parse().unwrap_or_else(|error| panic!("invalid mint fixture: {error}"));
|
||||
spl_associated_token_account_interface::instruction::create_associated_token_account(
|
||||
&fee_payer,
|
||||
&wallet_owner,
|
||||
&mint,
|
||||
&token_program,
|
||||
)
|
||||
},
|
||||
crate::ExSplAssociatedTokenAccountOperation::CreateIdempotent {
|
||||
wallet_owner,
|
||||
mint,
|
||||
token_program: _,
|
||||
} => {
|
||||
let wallet_owner = wallet_owner
|
||||
.0
|
||||
.parse()
|
||||
.unwrap_or_else(|error| panic!("invalid wallet fixture: {error}"));
|
||||
let mint =
|
||||
mint.0.parse().unwrap_or_else(|error| panic!("invalid mint fixture: {error}"));
|
||||
spl_associated_token_account_interface::instruction::create_associated_token_account_idempotent(
|
||||
&fee_payer,
|
||||
&wallet_owner,
|
||||
&mint,
|
||||
&token_program,
|
||||
)
|
||||
},
|
||||
crate::ExSplAssociatedTokenAccountOperation::RecoverNested {
|
||||
wallet_owner,
|
||||
owner_mint,
|
||||
nested_mint,
|
||||
token_program: _,
|
||||
} => {
|
||||
let wallet_owner = wallet_owner
|
||||
.0
|
||||
.parse()
|
||||
.unwrap_or_else(|error| panic!("invalid wallet fixture: {error}"));
|
||||
let owner_mint = owner_mint
|
||||
.0
|
||||
.parse()
|
||||
.unwrap_or_else(|error| panic!("invalid owner mint fixture: {error}"));
|
||||
let nested_mint = nested_mint
|
||||
.0
|
||||
.parse()
|
||||
.unwrap_or_else(|error| panic!("invalid nested mint fixture: {error}"));
|
||||
spl_associated_token_account_interface::instruction::recover_nested(
|
||||
&wallet_owner,
|
||||
&owner_mint,
|
||||
&nested_mint,
|
||||
&token_program,
|
||||
)
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn assert_matches_official(intent: &crate::ExSplAssociatedTokenAccountExecutionIntent) {
|
||||
let plan = crate::ExApiTypedInstructionExecutor::build_prepared_plan(
|
||||
&crate::ExSplAssociatedTokenAccountExecutor,
|
||||
intent,
|
||||
)
|
||||
.unwrap_or_else(|error| panic!("ATA plan failed: {error}"));
|
||||
let official = official_instruction(intent);
|
||||
assert_eq!(plan.instructions.len(), 1);
|
||||
let actual = &plan.instructions[0];
|
||||
assert_eq!(actual.program_id.0, official.program_id.to_string());
|
||||
assert_eq!(actual.data, official.data);
|
||||
assert_eq!(actual.accounts.len(), official.accounts.len());
|
||||
for (actual_account, official_account) in
|
||||
actual.accounts.iter().zip(official.accounts.iter())
|
||||
{
|
||||
assert_eq!(actual_account.pubkey.0, official_account.pubkey.to_string());
|
||||
assert_eq!(actual_account.is_signer, official_account.is_signer);
|
||||
assert_eq!(actual_account.is_writable, official_account.is_writable);
|
||||
}
|
||||
assert_eq!(plan.requested_spend_lamports, intent.max_rent_lamports);
|
||||
assert_eq!(plan.policy.simulation, crate::ExApiExecutionSimulationPolicy::Required);
|
||||
assert!(plan.policy.dry_run);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn every_variant_and_token_program_matches_the_official_builder() {
|
||||
for token_program in [
|
||||
crate::ExSplAssociatedTokenProgram::Classic,
|
||||
crate::ExSplAssociatedTokenProgram::Token2022,
|
||||
] {
|
||||
for operation in [
|
||||
crate::ExSplAssociatedTokenAccountOperation::Create {
|
||||
wallet_owner: pubkey(kb_program_ids::STAKE_PROGRAM_ID),
|
||||
mint: pubkey(kb_program_ids::VOTE_PROGRAM_ID),
|
||||
token_program,
|
||||
},
|
||||
crate::ExSplAssociatedTokenAccountOperation::CreateIdempotent {
|
||||
wallet_owner: pubkey(kb_program_ids::STAKE_PROGRAM_ID),
|
||||
mint: pubkey(kb_program_ids::VOTE_PROGRAM_ID),
|
||||
token_program,
|
||||
},
|
||||
] {
|
||||
let intent = intent(operation, 2_100_000);
|
||||
assert_matches_official(&intent);
|
||||
}
|
||||
let recovery = intent(
|
||||
crate::ExSplAssociatedTokenAccountOperation::RecoverNested {
|
||||
wallet_owner: pubkey(kb_program_ids::STAKE_PROGRAM_ID),
|
||||
owner_mint: pubkey(kb_program_ids::VOTE_PROGRAM_ID),
|
||||
nested_mint: pubkey(kb_program_ids::CONFIG_PROGRAM_ID),
|
||||
token_program,
|
||||
},
|
||||
0,
|
||||
);
|
||||
assert_matches_official(&recovery);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signer_set_is_unique_without_reordering_instruction_metas() {
|
||||
let intent = intent(
|
||||
crate::ExSplAssociatedTokenAccountOperation::RecoverNested {
|
||||
wallet_owner: pubkey(kb_program_ids::STAKE_PROGRAM_ID),
|
||||
owner_mint: pubkey(kb_program_ids::VOTE_PROGRAM_ID),
|
||||
nested_mint: pubkey(kb_program_ids::CONFIG_PROGRAM_ID),
|
||||
token_program: crate::ExSplAssociatedTokenProgram::Classic,
|
||||
},
|
||||
0,
|
||||
);
|
||||
let plan = crate::executor_spl_ata_build_prepared_plan(&intent)
|
||||
.unwrap_or_else(|error| panic!("ATA recovery plan failed: {error}"));
|
||||
assert_eq!(plan.required_signers.len(), 2);
|
||||
assert_eq!(plan.required_signers[0].role, "fee_payer");
|
||||
assert_eq!(plan.required_signers[1].role, "wallet_owner");
|
||||
assert_eq!(plan.instructions[0].accounts[5].pubkey, plan.required_signers[1].pubkey);
|
||||
assert!(plan.instructions[0].accounts[5].is_signer);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conservative_policy_rejects_unsafe_cost_and_replay_shapes() {
|
||||
let operation = crate::ExSplAssociatedTokenAccountOperation::Create {
|
||||
wallet_owner: pubkey(kb_program_ids::STAKE_PROGRAM_ID),
|
||||
mint: pubkey(kb_program_ids::VOTE_PROGRAM_ID),
|
||||
token_program: crate::ExSplAssociatedTokenProgram::Classic,
|
||||
};
|
||||
let mut intent = intent(operation, 2_100_000);
|
||||
intent.policy.simulation = crate::ExApiExecutionSimulationPolicy::Optional;
|
||||
let error = crate::executor_spl_ata_build_prepared_plan(&intent)
|
||||
.expect_err("optional simulation must fail");
|
||||
assert_eq!(error.code(), "execution_spl_ata_simulation_required");
|
||||
|
||||
intent.policy.simulation = crate::ExApiExecutionSimulationPolicy::Required;
|
||||
intent.policy.cost_limit.max_spend_lamports = std::option::Option::Some(1);
|
||||
let error = crate::executor_spl_ata_build_prepared_plan(&intent)
|
||||
.expect_err("mismatched spend ceiling must fail");
|
||||
assert_eq!(error.code(), "execution_spl_ata_spend_limit_mismatch");
|
||||
|
||||
intent.policy.cost_limit.max_spend_lamports = std::option::Option::Some(2_100_000);
|
||||
intent.policy.post_execution_validation.materialization_required = false;
|
||||
let error = crate::executor_spl_ata_build_prepared_plan(&intent)
|
||||
.expect_err("incomplete replay validation must fail");
|
||||
assert_eq!(error.code(), "execution_spl_ata_post_validation_required");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recovery_requires_zero_rent_and_creation_requires_a_positive_ceiling() {
|
||||
let create = intent(
|
||||
crate::ExSplAssociatedTokenAccountOperation::Create {
|
||||
wallet_owner: pubkey(kb_program_ids::STAKE_PROGRAM_ID),
|
||||
mint: pubkey(kb_program_ids::VOTE_PROGRAM_ID),
|
||||
token_program: crate::ExSplAssociatedTokenProgram::Classic,
|
||||
},
|
||||
0,
|
||||
);
|
||||
let error = crate::executor_spl_ata_build_prepared_plan(&create)
|
||||
.expect_err("zero creation ceiling must fail");
|
||||
assert_eq!(error.code(), "execution_spl_ata_rent_limit_missing");
|
||||
|
||||
let recovery = intent(
|
||||
crate::ExSplAssociatedTokenAccountOperation::RecoverNested {
|
||||
wallet_owner: pubkey(kb_program_ids::STAKE_PROGRAM_ID),
|
||||
owner_mint: pubkey(kb_program_ids::VOTE_PROGRAM_ID),
|
||||
nested_mint: pubkey(kb_program_ids::CONFIG_PROGRAM_ID),
|
||||
token_program: crate::ExSplAssociatedTokenProgram::Token2022,
|
||||
},
|
||||
1,
|
||||
);
|
||||
let error = crate::executor_spl_ata_build_prepared_plan(&recovery)
|
||||
.expect_err("recovery rent spending must fail");
|
||||
assert_eq!(error.code(), "execution_spl_ata_recovery_rent_must_be_zero");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// file: kb-lib/src/executor/spl/associated_token_account/constants.rs
|
||||
// version: 3
|
||||
|
||||
//! Local constants for the `kb_executor_spl_associated_token_account` crate. Program identifiers live in `kb_program_ids`.
|
||||
|
||||
/// Canonical tracing target for this crate.
|
||||
pub(crate) const EX_SPL_ATA_TRACING_TARGET: &str = "kb-lib.executor.spl.associated_token_account";
|
||||
282
kb-lib/src/executor/spl/associated_token_account/executor.rs
Normal file
282
kb-lib/src/executor/spl/associated_token_account/executor.rs
Normal file
@@ -0,0 +1,282 @@
|
||||
// file: kb-lib/src/executor/spl/associated_token_account/executor.rs
|
||||
// version: 4
|
||||
|
||||
//! Exact ATA capability dispatch and typed plan construction.
|
||||
|
||||
/// SPL Associated Token Account executor implementation.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct ExSplAssociatedTokenAccountExecutor;
|
||||
|
||||
impl crate::ExSplAssociatedTokenAccountExecutor {
|
||||
fn exact_capability(
|
||||
&self,
|
||||
program_id: &crate::MdProgramId,
|
||||
operation_code: &str,
|
||||
) -> crate::ExApiExecutionCapability {
|
||||
if program_id.0 != kb_program_ids::ASSOCIATED_TOKEN_PROGRAM_ID {
|
||||
return crate::ExApiExecutionCapability::unsupported(
|
||||
"execution_spl_ata_program_not_owned",
|
||||
format!(
|
||||
"program {} is not owned by kb_executor_spl_associated_token_account",
|
||||
program_id.0
|
||||
),
|
||||
);
|
||||
}
|
||||
if crate::EX_SPL_ATA_SUPPORTED_OPERATION_CODES.contains(&operation_code) {
|
||||
return crate::ExApiExecutionCapability::supported(operation_code);
|
||||
}
|
||||
return crate::ExApiExecutionCapability::unsupported(
|
||||
"execution_spl_ata_operation_unsupported",
|
||||
format!("SPL Associated Token Account operation {operation_code} is not implemented"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ExApiTypedInstructionExecutor for crate::ExSplAssociatedTokenAccountExecutor {
|
||||
type Intent = crate::ExSplAssociatedTokenAccountExecutionIntent;
|
||||
|
||||
fn capability(
|
||||
&self,
|
||||
program_id: &crate::MdProgramId,
|
||||
operation_code: &str,
|
||||
) -> crate::ExApiExecutionCapability {
|
||||
return self.exact_capability(program_id, operation_code);
|
||||
}
|
||||
|
||||
fn build_prepared_plan(
|
||||
&self,
|
||||
intent: &Self::Intent,
|
||||
) -> kb_core::Result<crate::ExApiPreparedExecutionPlan> {
|
||||
let program_id = crate::MdProgramId(std::string::String::from(
|
||||
kb_program_ids::ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||
));
|
||||
return match self.exact_capability(&program_id, intent.operation.operation_code()) {
|
||||
crate::ExApiExecutionCapability::Supported { operation_code: _ } => {
|
||||
crate::executor_spl_ata_build_prepared_plan(intent)
|
||||
},
|
||||
crate::ExApiExecutionCapability::Unsupported { reason_code, reason } => {
|
||||
std::result::Result::Err(kb_core::Error::new(reason_code, reason))
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::ExApiInstructionExecutor for crate::ExSplAssociatedTokenAccountExecutor {
|
||||
fn executor_name(&self) -> &'static str {
|
||||
return "kb_executor_spl_associated_token_account";
|
||||
}
|
||||
|
||||
fn executor_version(&self) -> &'static str {
|
||||
return env!("CARGO_PKG_VERSION");
|
||||
}
|
||||
|
||||
fn program_ids(&self) -> &'static [&'static str] {
|
||||
return &[kb_program_ids::ASSOCIATED_TOKEN_PROGRAM_ID];
|
||||
}
|
||||
|
||||
fn supports_request(
|
||||
&self,
|
||||
request: &crate::ExApiExecutionRequest,
|
||||
) -> crate::ExApiExecutionSupport {
|
||||
return match self.exact_capability(&request.program_id, &request.operation_code) {
|
||||
crate::ExApiExecutionCapability::Supported { operation_code: _ } => {
|
||||
crate::ExApiExecutionSupport::Yes
|
||||
},
|
||||
crate::ExApiExecutionCapability::Unsupported { reason_code: _, reason: _ } => {
|
||||
crate::ExApiExecutionSupport::No
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn build_plan(
|
||||
&self,
|
||||
request: &crate::ExApiExecutionRequest,
|
||||
) -> kb_core::Result<crate::ExApiExecutionPlan> {
|
||||
match self.exact_capability(&request.program_id, &request.operation_code) {
|
||||
crate::ExApiExecutionCapability::Supported { operation_code: _ } => {},
|
||||
crate::ExApiExecutionCapability::Unsupported { reason_code, reason } => {
|
||||
return std::result::Result::Err(kb_core::Error::new(reason_code, reason));
|
||||
},
|
||||
}
|
||||
let intent = match serde_json::from_str::<crate::ExSplAssociatedTokenAccountExecutionIntent>(
|
||||
&request.payload_json,
|
||||
) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_spl_ata_intent_deserialize_failed",
|
||||
error.to_string(),
|
||||
));
|
||||
},
|
||||
};
|
||||
if intent.operation.operation_code() != request.operation_code.as_str() {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_operation_code_mismatch",
|
||||
format!(
|
||||
"request operation {} does not match typed intent operation {}",
|
||||
request.operation_code,
|
||||
intent.operation.operation_code()
|
||||
),
|
||||
));
|
||||
}
|
||||
let prepared =
|
||||
match crate::ExApiTypedInstructionExecutor::build_prepared_plan(self, &intent) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let payload_value = match serde_json::to_value(&prepared) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return std::result::Result::Err(kb_core::Error::new(
|
||||
"execution_spl_ata_plan_serialize_failed",
|
||||
error.to_string(),
|
||||
));
|
||||
},
|
||||
};
|
||||
let payload_json = match crate::executor_api_serialize_payload_json(&payload_value) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
return std::result::Result::Ok(crate::ExApiExecutionPlan {
|
||||
executor_name: std::string::String::from("kb_executor_spl_associated_token_account"),
|
||||
instruction_count: prepared.instructions.len(),
|
||||
payload_json,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
fn pubkey(value: &str) -> crate::MdPubkey {
|
||||
return crate::MdPubkey(value.to_string());
|
||||
}
|
||||
|
||||
fn intent(
|
||||
operation: crate::ExSplAssociatedTokenAccountOperation,
|
||||
max_rent_lamports: u64,
|
||||
) -> crate::ExSplAssociatedTokenAccountExecutionIntent {
|
||||
let fee_payer = pubkey(kb_program_ids::SYSTEM_PROGRAM_ID);
|
||||
let wallet_owner = match &operation {
|
||||
crate::ExSplAssociatedTokenAccountOperation::Create { wallet_owner, .. }
|
||||
| crate::ExSplAssociatedTokenAccountOperation::CreateIdempotent {
|
||||
wallet_owner, ..
|
||||
}
|
||||
| crate::ExSplAssociatedTokenAccountOperation::RecoverNested { wallet_owner, .. } => {
|
||||
wallet_owner.clone()
|
||||
},
|
||||
};
|
||||
let mut authorized_signers = std::vec![fee_payer.clone()];
|
||||
if !authorized_signers.contains(&wallet_owner) {
|
||||
authorized_signers.push(wallet_owner);
|
||||
}
|
||||
return crate::ExSplAssociatedTokenAccountExecutionIntent {
|
||||
intent_id: "ata-intent-1".to_string(),
|
||||
fee_payer,
|
||||
max_rent_lamports,
|
||||
policy: crate::ExApiExecutionPolicy {
|
||||
simulation: crate::ExApiExecutionSimulationPolicy::Required,
|
||||
cost_limit: crate::ExApiExecutionCostLimit {
|
||||
max_spend_lamports: std::option::Option::Some(max_rent_lamports),
|
||||
max_fee_lamports: std::option::Option::Some(10_000),
|
||||
max_compute_unit_price_micro_lamports: std::option::Option::None,
|
||||
},
|
||||
authorized_signers,
|
||||
dry_run: true,
|
||||
post_execution_validation: crate::ExApiPostExecutionValidationPolicy {
|
||||
canonical_insert_required: true,
|
||||
core_extraction_required: true,
|
||||
decode_replay_required: true,
|
||||
materialization_required: true,
|
||||
},
|
||||
..crate::ExApiExecutionPolicy::default()
|
||||
},
|
||||
operation,
|
||||
};
|
||||
}
|
||||
|
||||
fn request(program_id: &str, operation_code: &str) -> crate::ExApiExecutionRequest {
|
||||
return crate::ExApiExecutionRequest {
|
||||
program_id: crate::MdProgramId(program_id.to_string()),
|
||||
operation_code: operation_code.to_string(),
|
||||
payload_json: std::string::String::from("{}"),
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exact_capabilities_cover_every_published_current_variant() {
|
||||
let executor = crate::ExSplAssociatedTokenAccountExecutor;
|
||||
for operation_code in crate::EX_SPL_ATA_SUPPORTED_OPERATION_CODES {
|
||||
let request = request(kb_program_ids::ASSOCIATED_TOKEN_PROGRAM_ID, operation_code);
|
||||
assert_eq!(
|
||||
crate::ExApiInstructionExecutor::supports_request(&executor, &request),
|
||||
crate::ExApiExecutionSupport::Yes
|
||||
);
|
||||
}
|
||||
for (program_id, operation_code) in [
|
||||
(kb_program_ids::SYSTEM_PROGRAM_ID, crate::EX_SPL_ATA_CREATE_OPERATION),
|
||||
(
|
||||
kb_program_ids::ASSOCIATED_TOKEN_PROGRAM_ID,
|
||||
"spl_associated_token_account.close",
|
||||
),
|
||||
] {
|
||||
let request = request(program_id, operation_code);
|
||||
assert_eq!(
|
||||
crate::ExApiInstructionExecutor::supports_request(&executor, &request),
|
||||
crate::ExApiExecutionSupport::No
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn generic_request_roundtrips_one_typed_instruction() {
|
||||
let pintent = intent(
|
||||
crate::ExSplAssociatedTokenAccountOperation::CreateIdempotent {
|
||||
wallet_owner: pubkey(kb_program_ids::STAKE_PROGRAM_ID),
|
||||
mint: pubkey(kb_program_ids::VOTE_PROGRAM_ID),
|
||||
token_program: crate::ExSplAssociatedTokenProgram::Token2022,
|
||||
},
|
||||
2_100_000,
|
||||
);
|
||||
let payload_json = serde_json::to_string(&pintent)
|
||||
.unwrap_or_else(|error| panic!("ATA intent serialization failed: {error}"));
|
||||
let request = crate::ExApiExecutionRequest {
|
||||
program_id: crate::MdProgramId(kb_program_ids::ASSOCIATED_TOKEN_PROGRAM_ID.to_string()),
|
||||
operation_code: crate::EX_SPL_ATA_CREATE_IDEMPOTENT_OPERATION.to_string(),
|
||||
payload_json,
|
||||
};
|
||||
let plan = crate::ExApiInstructionExecutor::build_plan(
|
||||
&crate::ExSplAssociatedTokenAccountExecutor,
|
||||
&request,
|
||||
)
|
||||
.unwrap_or_else(|error| panic!("generic ATA plan failed: {error}"));
|
||||
assert_eq!(plan.instruction_count, 1);
|
||||
let prepared =
|
||||
serde_json::from_str::<crate::ExApiPreparedExecutionPlan>(&plan.payload_json)
|
||||
.unwrap_or_else(|error| panic!("prepared ATA plan parsing failed: {error}"));
|
||||
assert_eq!(prepared.operation_code, crate::EX_SPL_ATA_CREATE_IDEMPOTENT_OPERATION);
|
||||
assert_eq!(prepared.instructions[0].data, std::vec![1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn machine_readable_matrix_matches_compiled_executor_capabilities() {
|
||||
let matrix: serde_json::Value = serde_json::from_str(include_str!(
|
||||
"../../../../../docs/SPL_ASSOCIATED_TOKEN_ACCOUNT_MATRIX.json"
|
||||
))
|
||||
.unwrap_or_else(|error| panic!("ATA matrix parsing failed: {error}"));
|
||||
let instructions = matrix["instructions"]
|
||||
.as_array()
|
||||
.unwrap_or_else(|| panic!("ATA matrix instructions must be an array"));
|
||||
let matrix_operations = instructions
|
||||
.iter()
|
||||
.map(|instruction| {
|
||||
assert_eq!(instruction["executorSupport"]["status"], "supported");
|
||||
return instruction["executorSupport"]["operationCode"]
|
||||
.as_str()
|
||||
.unwrap_or_else(|| panic!("ATA operation code must be a string"));
|
||||
})
|
||||
.collect::<std::vec::Vec<_>>();
|
||||
assert_eq!(matrix_operations, crate::EX_SPL_ATA_SUPPORTED_OPERATION_CODES);
|
||||
assert_eq!(matrix["surfaceEquality"]["matrixVariantCount"], 3);
|
||||
assert_eq!(matrix["surfaceEquality"]["officialInterfaceVariantCount"], 3);
|
||||
}
|
||||
}
|
||||
126
kb-lib/src/executor/spl/associated_token_account/intent.rs
Normal file
126
kb-lib/src/executor/spl/associated_token_account/intent.rs
Normal file
@@ -0,0 +1,126 @@
|
||||
// file: kb-lib/src/executor/spl/associated_token_account/intent.rs
|
||||
// version: 2
|
||||
|
||||
//! Typed SPL Associated Token Account execution intents.
|
||||
|
||||
use ts_rs::TS; // rust-rules: derive-import
|
||||
|
||||
/// Stable operation code for strict ATA creation.
|
||||
pub const EX_SPL_ATA_CREATE_OPERATION: &str = "spl_associated_token_account.create";
|
||||
/// Stable operation code for idempotent ATA creation or reuse.
|
||||
pub const EX_SPL_ATA_CREATE_IDEMPOTENT_OPERATION: &str =
|
||||
"spl_associated_token_account.create_idempotent";
|
||||
/// Stable operation code for nested ATA recovery.
|
||||
pub const EX_SPL_ATA_RECOVER_NESTED_OPERATION: &str = "spl_associated_token_account.recover_nested";
|
||||
/// Every current officially constructible ATA operation.
|
||||
pub const EX_SPL_ATA_SUPPORTED_OPERATION_CODES: &[&str] = &[
|
||||
EX_SPL_ATA_CREATE_OPERATION,
|
||||
EX_SPL_ATA_CREATE_IDEMPOTENT_OPERATION,
|
||||
EX_SPL_ATA_RECOVER_NESTED_OPERATION,
|
||||
];
|
||||
|
||||
/// Exact Token Program targeted by ATA derivation and runtime CPIs.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/spl/associated_token_account/intent/ExSplAssociatedTokenProgram.ts"
|
||||
)]
|
||||
pub enum ExSplAssociatedTokenProgram {
|
||||
/// Classic SPL Token program.
|
||||
Classic,
|
||||
/// Token-2022 program without extension-specific executor semantics.
|
||||
Token2022,
|
||||
}
|
||||
|
||||
impl crate::ExSplAssociatedTokenProgram {
|
||||
/// Returns the exact target Token Program ID.
|
||||
pub fn program_id(&self) -> &'static str {
|
||||
return match self {
|
||||
Self::Classic => kb_program_ids::SPL_TOKEN_PROGRAM_ID,
|
||||
Self::Token2022 => kb_program_ids::SPL_TOKEN2022_PROGRAM_ID,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// One officially constructible ATA operation.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[serde(tag = "operation", rename_all = "snake_case")]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/spl/associated_token_account/intent/ExSplAssociatedTokenAccountOperation.ts"
|
||||
)]
|
||||
pub enum ExSplAssociatedTokenAccountOperation {
|
||||
/// Strictly create an absent canonical ATA.
|
||||
Create {
|
||||
/// Wallet owner used as the first PDA seed.
|
||||
wallet_owner: crate::MdPubkey,
|
||||
/// Mint used as the third PDA seed.
|
||||
mint: crate::MdPubkey,
|
||||
/// Token Program used as the second PDA seed and runtime CPI target.
|
||||
token_program: crate::ExSplAssociatedTokenProgram,
|
||||
},
|
||||
/// Create an absent ATA or accept an existing compatible ATA.
|
||||
CreateIdempotent {
|
||||
/// Wallet owner used as the first PDA seed.
|
||||
wallet_owner: crate::MdPubkey,
|
||||
/// Mint used as the third PDA seed.
|
||||
mint: crate::MdPubkey,
|
||||
/// Token Program used as the second PDA seed and runtime CPI target.
|
||||
token_program: crate::ExSplAssociatedTokenProgram,
|
||||
},
|
||||
/// Recover tokens and lamports from one canonical nested ATA.
|
||||
RecoverNested {
|
||||
/// Wallet owner that must sign the recovery.
|
||||
wallet_owner: crate::MdPubkey,
|
||||
/// Mint whose ATA currently owns the nested ATA.
|
||||
owner_mint: crate::MdPubkey,
|
||||
/// Mint held by the nested ATA and the wallet destination ATA.
|
||||
nested_mint: crate::MdPubkey,
|
||||
/// Token Program shared by all three derived ATA addresses.
|
||||
token_program: crate::ExSplAssociatedTokenProgram,
|
||||
},
|
||||
}
|
||||
|
||||
impl crate::ExSplAssociatedTokenAccountOperation {
|
||||
/// Returns the stable generic dispatch operation code.
|
||||
pub fn operation_code(&self) -> &'static str {
|
||||
return match self {
|
||||
Self::Create { .. } => crate::EX_SPL_ATA_CREATE_OPERATION,
|
||||
Self::CreateIdempotent { .. } => crate::EX_SPL_ATA_CREATE_IDEMPOTENT_OPERATION,
|
||||
Self::RecoverNested { .. } => crate::EX_SPL_ATA_RECOVER_NESTED_OPERATION,
|
||||
};
|
||||
}
|
||||
|
||||
/// Returns the exact target Token Program.
|
||||
pub fn token_program(&self) -> crate::ExSplAssociatedTokenProgram {
|
||||
return match self {
|
||||
Self::Create { token_program, .. }
|
||||
| Self::CreateIdempotent { token_program, .. }
|
||||
| Self::RecoverNested { token_program, .. } => *token_program,
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) fn is_creation(&self) -> bool {
|
||||
return matches!(self, Self::Create { .. } | Self::CreateIdempotent { .. });
|
||||
}
|
||||
}
|
||||
|
||||
/// Complete typed intent accepted by the ATA executor.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_lib/executor/spl/associated_token_account/intent/ExSplAssociatedTokenAccountExecutionIntent.ts"
|
||||
)]
|
||||
pub struct ExSplAssociatedTokenAccountExecutionIntent {
|
||||
/// Stable caller-provided identifier used for logs and replay correlation.
|
||||
pub intent_id: std::string::String,
|
||||
/// Transaction fee payer and Create/CreateIdempotent funding account.
|
||||
pub fee_payer: crate::MdPubkey,
|
||||
/// Maximum rent lamports the creation operation may spend; zero for RecoverNested.
|
||||
pub max_rent_lamports: u64,
|
||||
/// Conservative common execution policy.
|
||||
pub policy: crate::ExApiExecutionPolicy,
|
||||
/// Typed ATA operation and exact address inputs.
|
||||
pub operation: crate::ExSplAssociatedTokenAccountOperation,
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/lib.rs
|
||||
// version: 19
|
||||
// version: 20
|
||||
|
||||
//! Consolidated decoder, executor, materializer and shared model library.
|
||||
#![warn(missing_docs)]
|
||||
@@ -563,6 +563,14 @@ pub use self::executor::EX_SOLANA_CORE_ZK_ELGAMAL_CLOSE_CONTEXT_STATE_OPERATION;
|
||||
pub use self::executor::EX_SOLANA_CORE_ZK_ELGAMAL_VERIFY_FROM_ACCOUNT_OPERATION;
|
||||
/// Exposes the ZK ElGamal inline proof verification operation code.
|
||||
pub use self::executor::EX_SOLANA_CORE_ZK_ELGAMAL_VERIFY_INLINE_OPERATION;
|
||||
/// Exposes the idempotent ATA creation operation code.
|
||||
pub use self::executor::EX_SPL_ATA_CREATE_IDEMPOTENT_OPERATION;
|
||||
/// Exposes the strict ATA creation operation code.
|
||||
pub use self::executor::EX_SPL_ATA_CREATE_OPERATION;
|
||||
/// Exposes the nested ATA recovery operation code.
|
||||
pub use self::executor::EX_SPL_ATA_RECOVER_NESTED_OPERATION;
|
||||
/// Exposes every supported ATA operation code.
|
||||
pub use self::executor::EX_SPL_ATA_SUPPORTED_OPERATION_CODES;
|
||||
/// Exposes the stable SPL Memo add-memo operation code.
|
||||
pub use self::executor::EX_SPL_MEMO_ADD_MEMO_OPERATION;
|
||||
/// Exposes the SPL Memo payload bound.
|
||||
@@ -807,8 +815,14 @@ pub use self::executor::ExSolanaCoreZkElGamalContextState;
|
||||
pub use self::executor::ExSolanaCoreZkElGamalProofType;
|
||||
/// Exposes the reserved `ExSplAccountCompressionExecutor` implementation.
|
||||
pub use self::executor::ExSplAccountCompressionExecutor;
|
||||
/// Exposes the reserved `ExSplAssociatedTokenAccountExecutor` implementation.
|
||||
/// Exposes the typed SPL ATA execution intent.
|
||||
pub use self::executor::ExSplAssociatedTokenAccountExecutionIntent;
|
||||
/// Exposes the SPL ATA executor implementation.
|
||||
pub use self::executor::ExSplAssociatedTokenAccountExecutor;
|
||||
/// Exposes one typed SPL ATA operation.
|
||||
pub use self::executor::ExSplAssociatedTokenAccountOperation;
|
||||
/// Exposes the exact Token Program used by ATA derivation.
|
||||
pub use self::executor::ExSplAssociatedTokenProgram;
|
||||
/// Exposes the reserved `ExSplElgamalRegistryExecutor` implementation.
|
||||
pub use self::executor::ExSplElgamalRegistryExecutor;
|
||||
/// Exposes the typed SPL Memo execution intent.
|
||||
@@ -1435,6 +1449,8 @@ pub(crate) use self::decoder::decoder_spl_token2022_payload_tag;
|
||||
/// Canonical tracing target for this crate.
|
||||
pub(crate) use self::executor::EX_SOLANA_CORE_TRACING_TARGET;
|
||||
/// Canonical SPL Memo tracing target.
|
||||
pub(crate) use self::executor::EX_SPL_ATA_TRACING_TARGET;
|
||||
/// Canonical SPL Memo tracing target.
|
||||
pub(crate) use self::executor::EX_SPL_MEMO_TRACING_TARGET;
|
||||
/// Crate-root access to `build_prepared_plan` from `address_lookup_table`.
|
||||
pub(crate) use self::executor::executor_solana_core_address_lookup_table_build_prepared_plan;
|
||||
@@ -1473,6 +1489,8 @@ pub(crate) use self::executor::executor_solana_core_vote_build_prepared_plan;
|
||||
/// Crate-root access to `build_prepared_plan` from `zk_elgamal`.
|
||||
pub(crate) use self::executor::executor_solana_core_zk_elgamal_build_prepared_plan;
|
||||
/// Internal SPL Memo plan builder.
|
||||
pub(crate) use self::executor::executor_spl_ata_build_prepared_plan;
|
||||
/// Internal SPL Memo plan builder.
|
||||
pub(crate) use self::executor::executor_spl_memo_build_prepared_plan;
|
||||
/// Canonical processor name for the native and SPL administration materializer.
|
||||
pub(crate) use self::materializer::MT_ADMIN_PROCESSOR_NAME;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/model/decoded.rs
|
||||
// version: 4
|
||||
// version: 5
|
||||
|
||||
//! Shared decoded protocol event model.
|
||||
|
||||
@@ -9,7 +9,7 @@ use ts_rs::TS; // rust-rules: derive-import
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_model/decoded/EventSourceKind.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/model/decoded/EventSourceKind.ts"
|
||||
)]
|
||||
pub enum MdEventSourceKind {
|
||||
/// Top-level instruction.
|
||||
@@ -36,7 +36,7 @@ pub enum MdEventSourceKind {
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_model/decoded/DecoderConfidence.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/model/decoded/DecoderConfidence.ts"
|
||||
)]
|
||||
pub enum MdDecoderConfidence {
|
||||
/// Exact manual decode.
|
||||
@@ -59,7 +59,7 @@ pub enum MdDecoderConfidence {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_model/decoded/DecodedProtocolEvent.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/model/decoded/DecodedProtocolEvent.ts"
|
||||
)]
|
||||
pub struct MdDecodedProtocolEvent {
|
||||
/// Transaction signature.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/model/materialized.rs
|
||||
// version: 5
|
||||
// version: 6
|
||||
|
||||
//! Shared materialized business event model.
|
||||
|
||||
@@ -9,7 +9,7 @@ use ts_rs::TS; // rust-rules: derive-import
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_model/materialized/MaterializedEventFamily.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/model/materialized/MaterializedEventFamily.ts"
|
||||
)]
|
||||
pub enum MdMaterializedEventFamily {
|
||||
/// Trade materialization.
|
||||
@@ -66,7 +66,7 @@ pub enum MdMaterializedEventFamily {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_model/materialized/MaterializedEvent.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/model/materialized/MaterializedEvent.ts"
|
||||
)]
|
||||
pub struct MdMaterializedEvent {
|
||||
/// Source transaction signature.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/model/nomenclature.rs
|
||||
// version: 3
|
||||
// version: 4
|
||||
|
||||
//! Shared protocol, surface, and event nomenclature types.
|
||||
|
||||
@@ -9,7 +9,7 @@ use ts_rs::TS; // rust-rules: derive-import
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_model/nomenclature/ProgramCode.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/model/nomenclature/ProgramCode.ts"
|
||||
)]
|
||||
pub struct MdProgramCode(pub std::string::String);
|
||||
|
||||
@@ -17,7 +17,7 @@ pub struct MdProgramCode(pub std::string::String);
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_model/nomenclature/ProtocolCode.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/model/nomenclature/ProtocolCode.ts"
|
||||
)]
|
||||
pub struct MdProtocolCode(pub std::string::String);
|
||||
|
||||
@@ -25,25 +25,25 @@ pub struct MdProtocolCode(pub std::string::String);
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_model/nomenclature/SurfaceCode.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/model/nomenclature/SurfaceCode.ts"
|
||||
)]
|
||||
pub struct MdSurfaceCode(pub std::string::String);
|
||||
|
||||
/// Event name without surface prefix.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/kb_model/nomenclature/EventName.ts")]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/kb_lib/model/nomenclature/EventName.ts")]
|
||||
pub struct MdEventName(pub std::string::String);
|
||||
|
||||
/// Canonical event code in `<surface_code>.<event_name>` format.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/kb_model/nomenclature/EventCode.ts")]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/kb_lib/model/nomenclature/EventCode.ts")]
|
||||
pub struct MdEventCode(pub std::string::String);
|
||||
|
||||
/// High-level event family.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_model/nomenclature/EventFamily.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/model/nomenclature/EventFamily.ts"
|
||||
)]
|
||||
pub enum MdEventFamily {
|
||||
/// Swap or buy/sell event.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/model/observation.rs
|
||||
// version: 4
|
||||
// version: 5
|
||||
|
||||
//! Shared program observation model.
|
||||
|
||||
@@ -9,7 +9,7 @@ use ts_rs::TS; // rust-rules: derive-import
|
||||
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(
|
||||
export,
|
||||
export_to = "../frontend/ts/bindings/kb_model/observation/ProgramObservation.ts"
|
||||
export_to = "../frontend/ts/bindings/kb_lib/model/observation/ProgramObservation.ts"
|
||||
)]
|
||||
pub struct MdProgramObservation {
|
||||
/// Transaction signature.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: kb-lib/src/model/solana.rs
|
||||
// version: 3
|
||||
// version: 4
|
||||
|
||||
//! Shared Solana primitive wrapper types.
|
||||
|
||||
@@ -7,7 +7,7 @@ use ts_rs::TS; // rust-rules: derive-import
|
||||
|
||||
/// Solana transaction signature.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/kb_model/solana/Signature.ts")]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/kb_lib/model/solana/Signature.ts")]
|
||||
pub struct MdSignature(pub std::string::String);
|
||||
|
||||
/// Solana slot.
|
||||
@@ -24,20 +24,20 @@ pub struct MdSignature(pub std::string::String);
|
||||
serde::Serialize,
|
||||
TS,
|
||||
)]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/kb_model/solana/Slot.ts")]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/kb_lib/model/solana/Slot.ts")]
|
||||
pub struct MdSlot(pub u64);
|
||||
|
||||
/// Solana program id.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/kb_model/solana/ProgramId.ts")]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/kb_lib/model/solana/ProgramId.ts")]
|
||||
pub struct MdProgramId(pub std::string::String);
|
||||
|
||||
/// Solana public key.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/kb_model/solana/Pubkey.ts")]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/kb_lib/model/solana/Pubkey.ts")]
|
||||
pub struct MdPubkey(pub std::string::String);
|
||||
|
||||
/// Stable top-level or inner instruction path.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash, serde::Deserialize, serde::Serialize, TS)]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/kb_model/solana/InstructionPath.ts")]
|
||||
#[ts(export, export_to = "../frontend/ts/bindings/kb_lib/model/solana/InstructionPath.ts")]
|
||||
pub struct MdInstructionPath(pub std::string::String);
|
||||
|
||||
Reference in New Issue
Block a user