starknet_api 0.18.0-rc.1

Starknet Rust types related to computation and execution.
Documentation
use super::TestingTxArgs;
use crate::abi::abi_utils::selector_from_name;
use crate::calldata;
use crate::core::{ContractAddress, Nonce};
use crate::data_availability::DataAvailabilityMode;
use crate::executable_transaction::{
    AccountTransaction,
    InvokeTransaction as ExecutableInvokeTransaction,
};
use crate::rpc_transaction::{
    InternalRpcTransaction,
    InternalRpcTransactionWithoutTxHash,
    RpcInvokeTransaction,
    RpcInvokeTransactionV3,
    RpcTransaction,
};
use crate::transaction::constants::EXECUTE_ENTRY_POINT_NAME;
use crate::transaction::fields::{
    AccountDeploymentData,
    Calldata,
    Fee,
    PaymasterData,
    Proof,
    ProofFacts,
    Tip,
    TransactionSignature,
    ValidResourceBounds,
};
use crate::transaction::{
    InvokeTransaction,
    InvokeTransactionV0,
    InvokeTransactionV1,
    InvokeTransactionV3,
    TransactionHash,
    TransactionVersion,
};

#[derive(Clone)]
pub struct InvokeTxArgs {
    pub max_fee: Fee,
    pub signature: TransactionSignature,
    pub sender_address: ContractAddress,
    pub calldata: Calldata,
    pub version: TransactionVersion,
    pub resource_bounds: ValidResourceBounds,
    pub tip: Tip,
    pub nonce_data_availability_mode: DataAvailabilityMode,
    pub fee_data_availability_mode: DataAvailabilityMode,
    pub paymaster_data: PaymasterData,
    pub account_deployment_data: AccountDeploymentData,
    pub nonce: Nonce,
    pub only_query: bool,
    pub tx_hash: TransactionHash,
    pub proof_facts: ProofFacts,
    pub proof: Proof,
}

impl Default for InvokeTxArgs {
    fn default() -> Self {
        InvokeTxArgs {
            max_fee: Fee::default(),
            signature: TransactionSignature::default(),
            sender_address: ContractAddress::default(),
            calldata: calldata![],
            version: TransactionVersion::THREE,
            resource_bounds: ValidResourceBounds::create_for_testing(),
            tip: Tip::default(),
            nonce_data_availability_mode: DataAvailabilityMode::L1,
            fee_data_availability_mode: DataAvailabilityMode::L1,
            paymaster_data: PaymasterData::default(),
            account_deployment_data: AccountDeploymentData::default(),
            nonce: Nonce::default(),
            only_query: false,
            tx_hash: TransactionHash::default(),
            proof_facts: ProofFacts::default(),
            proof: Proof::default(),
        }
    }
}

/// Utility macro for creating `InvokeTxArgs` to reduce boilerplate.
#[macro_export]
macro_rules! invoke_tx_args {
    ($($field:ident $(: $value:expr)?),* $(,)?) => {
        $crate::test_utils::invoke::InvokeTxArgs {
            $($field $(: $value)?,)*
            ..Default::default()
        }
    };
    ($($field:ident $(: $value:expr)?),* , ..$defaults:expr) => {
        $crate::test_utils::invoke::InvokeTxArgs {
            $($field $(: $value)?,)*
            ..$defaults
        }
    };
}

pub fn invoke_tx(invoke_args: InvokeTxArgs) -> InvokeTransaction {
    // TODO(Arni): Make TransactionVersion an enum and use match here.
    if invoke_args.version == TransactionVersion::ZERO {
        InvokeTransaction::V0(InvokeTransactionV0 {
            max_fee: invoke_args.max_fee,
            calldata: invoke_args.calldata,
            contract_address: invoke_args.sender_address,
            signature: invoke_args.signature,
            // V0 transactions should always select the `__execute__` entry point.
            entry_point_selector: selector_from_name(EXECUTE_ENTRY_POINT_NAME),
        })
    } else if invoke_args.version == TransactionVersion::ONE {
        InvokeTransaction::V1(InvokeTransactionV1 {
            max_fee: invoke_args.max_fee,
            sender_address: invoke_args.sender_address,
            nonce: invoke_args.nonce,
            calldata: invoke_args.calldata,
            signature: invoke_args.signature,
        })
    } else if invoke_args.version == TransactionVersion::THREE {
        InvokeTransaction::V3(InvokeTransactionV3 {
            resource_bounds: invoke_args.resource_bounds,
            calldata: invoke_args.calldata,
            sender_address: invoke_args.sender_address,
            nonce: invoke_args.nonce,
            signature: invoke_args.signature,
            tip: invoke_args.tip,
            nonce_data_availability_mode: invoke_args.nonce_data_availability_mode,
            fee_data_availability_mode: invoke_args.fee_data_availability_mode,
            paymaster_data: invoke_args.paymaster_data,
            account_deployment_data: invoke_args.account_deployment_data,
            proof_facts: invoke_args.proof_facts,
        })
    } else {
        panic!("Unsupported transaction version: {:?}.", invoke_args.version)
    }
}

pub fn executable_invoke_tx(invoke_args: InvokeTxArgs) -> AccountTransaction {
    let tx_hash = invoke_args.tx_hash;
    let tx = invoke_tx(invoke_args);
    let invoke_tx = ExecutableInvokeTransaction { tx, tx_hash };

    AccountTransaction::Invoke(invoke_tx)
}

pub fn rpc_invoke_tx(invoke_args: InvokeTxArgs) -> RpcTransaction {
    if invoke_args.version != TransactionVersion::THREE {
        panic!("Unsupported transaction version: {:?}.", invoke_args.version);
    }

    let ValidResourceBounds::AllResources(resource_bounds) = invoke_args.resource_bounds else {
        panic!("Unspported resource bounds type: {:?}.", invoke_args.resource_bounds)
    };

    RpcTransaction::Invoke(RpcInvokeTransaction::V3(RpcInvokeTransactionV3 {
        resource_bounds,
        tip: invoke_args.tip,
        calldata: invoke_args.calldata,
        sender_address: invoke_args.sender_address,
        nonce: invoke_args.nonce,
        signature: invoke_args.signature,
        nonce_data_availability_mode: invoke_args.nonce_data_availability_mode,
        fee_data_availability_mode: invoke_args.fee_data_availability_mode,
        paymaster_data: invoke_args.paymaster_data,
        account_deployment_data: invoke_args.account_deployment_data,
        proof_facts: invoke_args.proof_facts,
        proof: invoke_args.proof,
    }))
}

pub fn internal_invoke_tx(invoke_args: InvokeTxArgs) -> InternalRpcTransaction {
    if invoke_args.version != TransactionVersion::THREE {
        panic!("Unsupported transaction version: {:?}.", invoke_args.version);
    }
    let tx_hash = invoke_args.tx_hash;
    let RpcTransaction::Invoke(tx) = rpc_invoke_tx(invoke_args) else {
        panic!("Expected RpcTransaction::Invoke");
    };

    let invoke_tx = InternalRpcTransactionWithoutTxHash::Invoke(tx.into());

    InternalRpcTransaction { tx: invoke_tx, tx_hash }
}

impl TestingTxArgs for InvokeTxArgs {
    fn get_rpc_tx(&self) -> RpcTransaction {
        rpc_invoke_tx(self.clone())
    }

    fn get_internal_tx(&self) -> InternalRpcTransaction {
        internal_invoke_tx(self.clone())
    }

    fn get_executable_tx(&self) -> AccountTransaction {
        executable_invoke_tx(self.clone())
    }
}

// TODO(Itamar): Change this to use a macro and apply the same logic to DeclareTxArgs and
// DeployAccountTxArgs.
impl InvokeTxArgs {
    pub fn signature(mut self, signature: TransactionSignature) -> Self {
        self.signature = signature;
        self
    }

    pub fn sender_address(mut self, sender_address: ContractAddress) -> Self {
        self.sender_address = sender_address;
        self
    }

    pub fn calldata(mut self, calldata: Calldata) -> Self {
        self.calldata = calldata;
        self
    }

    pub fn resource_bounds(mut self, resource_bounds: ValidResourceBounds) -> Self {
        self.resource_bounds = resource_bounds;
        self
    }

    pub fn tip(mut self, tip: Tip) -> Self {
        self.tip = tip;
        self
    }

    pub fn nonce(mut self, nonce: Nonce) -> Self {
        self.nonce = nonce;
        self
    }
}