Skip to main content

ab_contracts_test_utils/
transaction_builder.rs

1use ab_contracts_common::method::ExternalArgs;
2use ab_core_primitives::address::Address;
3use ab_core_primitives::block::BlockRoot;
4use ab_core_primitives::transaction::owned::{OwnedTransaction, OwnedTransactionError};
5use ab_core_primitives::transaction::{Gas, TransactionHeader, TransactionSlot};
6use ab_system_contract_simple_wallet_base::payload::TransactionMethodContext;
7use ab_system_contract_simple_wallet_base::payload::builder::{
8    MethodCallReferences, TransactionPayloadBuilder, TransactionPayloadBuilderError,
9};
10
11/// Errors for [`TransactionBuilder::build()`]
12#[derive(Debug, thiserror::Error)]
13pub enum TransactionBuilderError {
14    /// Failed to build the payload
15    #[error("Failed to build the payload: {0}")]
16    Payload(TransactionPayloadBuilderError<'static>),
17    /// Failed to create the transaction
18    #[error("Failed to create the transaction: {0}")]
19    Transaction(OwnedTransactionError),
20}
21
22#[derive(Debug)]
23pub struct TransactionBuilder {
24    contract: Address,
25    transaction_payload_builder: TransactionPayloadBuilder,
26}
27
28impl TransactionBuilder {
29    /// Create a transaction for `contract` with a payload of up to `max_payload_size` bytes that
30    /// declares `num_outputs` outputs.
31    ///
32    /// See [`TransactionPayloadBuilder::new()`] for details of `max_payload_size` and
33    /// `num_outputs`.
34    pub fn new(
35        contract: Address,
36        max_payload_size: u32,
37        num_outputs: u8,
38    ) -> Result<Self, TransactionPayloadBuilderError<'static>> {
39        Ok(Self {
40            contract,
41            transaction_payload_builder: TransactionPayloadBuilder::new(
42                max_payload_size,
43                num_outputs,
44            )?,
45        })
46    }
47
48    /// Add method call to the transaction.
49    ///
50    /// See [`TransactionPayloadBuilder::with_method_call()`] for details of this API.
51    pub fn with_method_call<Args>(
52        &mut self,
53        contract: &Address,
54        external_args: &Args,
55        method_context: TransactionMethodContext,
56        references: MethodCallReferences<'_>,
57    ) -> Result<(), TransactionPayloadBuilderError<'static>>
58    where
59        Args: ExternalArgs,
60    {
61        self.transaction_payload_builder.with_method_call(
62            contract,
63            external_args,
64            method_context,
65            references,
66        )
67    }
68
69    /// Build the transaction.
70    ///
71    /// See [`TransactionPayloadBuilder::into_aligned_bytes()`] and
72    /// [`OwnedTransaction::from_parts()`] for errors.
73    pub fn build(
74        self,
75        read_slots: &[TransactionSlot],
76        write_slots: &[TransactionSlot],
77    ) -> Result<OwnedTransaction, TransactionBuilderError> {
78        let header = TransactionHeader {
79            version: 0,
80            block_root: BlockRoot::default(),
81            gas_limit: Gas::default(),
82            contract: self.contract,
83        };
84        let payload = self
85            .transaction_payload_builder
86            .into_aligned_bytes()
87            .map_err(TransactionBuilderError::Payload)?;
88
89        OwnedTransaction::from_parts(
90            &header,
91            read_slots,
92            write_slots,
93            payload.as_u128_slice(),
94            &[],
95        )
96        .map_err(TransactionBuilderError::Transaction)
97    }
98}