@@ -15,6 +15,10 @@ import utils from './utils';
1515import { TransactionObjectInput , GasData } from './iface' ;
1616import { toBase64 } from '@iota/iota-sdk/utils' ;
1717
18+ /**
19+ * Base class for IOTA transaction builders.
20+ * Provides common functionality for building and validating IOTA transactions.
21+ */
1822export abstract class TransactionBuilder extends BaseTransactionBuilder {
1923 protected _transaction : Transaction ;
2024
@@ -23,12 +27,18 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
2327 }
2428
2529 /**
26- * Initialize the transaction builder fields using the decoded transaction data
27- *
28- * @param {Transaction } tx the transaction data
30+ * Initializes the transaction builder with data from an existing transaction.
31+ * Copies sender, gas data, and gas sponsor information.
2932 */
3033 initBuilder ( tx : Transaction ) : void {
3134 this . validateTransaction ( tx ) ;
35+ this . copyTransactionData ( tx ) ;
36+ }
37+
38+ /**
39+ * Copies transaction data from the source transaction to the builder's transaction.
40+ */
41+ private copyTransactionData ( tx : Transaction ) : void {
3242 this . transaction . sender = tx . sender ;
3343 this . transaction . gasPrice = tx . gasPrice ;
3444 this . transaction . gasBudget = tx . gasBudget ;
@@ -40,25 +50,18 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
4050 return this . transaction . type ;
4151 }
4252
43- /**
44- * @inheritdoc
45- * */
4653 get transaction ( ) : Transaction {
4754 return this . _transaction ;
4855 }
4956
50- /**
51- * @inheritdoc
52- * */
5357 protected set transaction ( transaction : Transaction ) {
5458 this . _transaction = transaction ;
5559 }
5660
5761 /**
58- * Sets the sender of this transaction.
59- *
60- * @param {string } senderAddress the account that is sending this transaction
61- * @returns {TransactionBuilder } This transaction builder
62+ * Sets the sender address for this transaction.
63+ * @param senderAddress - The IOTA address that is sending this transaction
64+ * @returns This transaction builder for method chaining
6265 */
6366 sender ( senderAddress : string ) : this {
6467 this . validateAddress ( { address : senderAddress } ) ;
@@ -67,70 +70,99 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
6770 }
6871
6972 /**
70- * Sets the gasData for this transaction.
71- *
72- * @param {string } gasData the gas details for this transaction
73- * @returns {TransactionBuilder } This transaction builder
73+ * Sets the gas data for this transaction (budget, price, and payment objects).
74+ * @param gasData - The gas configuration including budget, price, and payment objects
75+ * @returns This transaction builder for method chaining
7476 */
7577 gasData ( gasData : GasData ) : this {
7678 this . validateGasData ( gasData ) ;
79+ this . setGasDataOnTransaction ( gasData ) ;
80+ return this ;
81+ }
82+
83+ /**
84+ * Sets gas data fields on the transaction.
85+ */
86+ private setGasDataOnTransaction ( gasData : GasData ) : void {
7787 this . transaction . gasPrice = gasData . gasPrice ;
7888 this . transaction . gasBudget = gasData . gasBudget ;
7989 this . transaction . gasPaymentObjects = gasData . gasPaymentObjects as TransactionObjectInput [ ] ;
80- return this ;
8190 }
8291
8392 /**
84- * Sets the gasSponsor of this transaction.
85- *
86- * @param { string } sponsorAddress the account that is sponsoring this transaction's gas
87- * @returns { TransactionBuilder } This transaction builder
93+ * Sets the gas sponsor for this transaction.
94+ * The gas sponsor pays for transaction fees instead of the sender.
95+ * @param sponsorAddress - The IOTA address sponsoring this transaction's gas fees
96+ * @returns This transaction builder for method chaining
8897 */
8998 gasSponsor ( sponsorAddress : string ) : this {
9099 this . validateAddress ( { address : sponsorAddress } ) ;
91100 this . transaction . gasSponsor = sponsorAddress ;
92101 return this ;
93102 }
94103
104+ /**
105+ * Adds a signature from the transaction sender.
106+ * @param publicKey - The sender's public key
107+ * @param signature - The signature bytes
108+ * @throws BuildTransactionError if the signature or public key is invalid
109+ */
95110 addSignature ( publicKey : PublicKey , signature : Buffer ) : void {
96- if ( ! utils . isValidPublicKey ( publicKey . pub ) || ! utils . isValidSignature ( toBase64 ( signature ) ) ) {
97- throw new BuildTransactionError ( 'Invalid transaction signature' ) ;
98- }
111+ this . validateSignatureData ( publicKey , signature ) ;
99112 this . transaction . addSignature ( publicKey , signature ) ;
100113 }
101114
115+ /**
116+ * Adds a signature from the gas sponsor.
117+ * @param publicKey - The gas sponsor's public key
118+ * @param signature - The signature bytes
119+ * @throws BuildTransactionError if the signature or public key is invalid
120+ */
102121 addGasSponsorSignature ( publicKey : PublicKey , signature : Buffer ) : void {
122+ this . validateSignatureData ( publicKey , signature ) ;
123+ this . transaction . addGasSponsorSignature ( publicKey , signature ) ;
124+ }
125+
126+ /**
127+ * Validates that the signature and public key are in valid formats.
128+ */
129+ private validateSignatureData ( publicKey : PublicKey , signature : Buffer ) : void {
103130 if ( ! utils . isValidPublicKey ( publicKey . pub ) || ! utils . isValidSignature ( toBase64 ( signature ) ) ) {
104131 throw new BuildTransactionError ( 'Invalid transaction signature' ) ;
105132 }
106- this . transaction . addGasSponsorSignature ( publicKey , signature ) ;
107133 }
108134
109135 validateKey ( key : BaseKey ) : void {
110136 throw new Error ( 'Method not implemented.' ) ;
111137 }
112138
113139 /**
114- * @inheritdoc
115- * */
140+ * Validates an IOTA address format.
141+ * @throws BuildTransactionError if address is invalid
142+ */
116143 validateAddress ( address : BaseAddress , addressFormat ?: string ) : void {
117144 if ( ! utils . isValidAddress ( address . address ) ) {
118145 throw new BuildTransactionError ( 'Invalid address ' + address . address ) ;
119146 }
120147 }
121148
122149 /**
123- * @inheritdoc
124- * */
150+ * Validates that a numeric value is valid (not NaN and not negative).
151+ * @throws BuildTransactionError if value is invalid
152+ */
125153 validateValue ( value : BigNumber ) : void {
126154 if ( value . isNaN ( ) ) {
127155 throw new BuildTransactionError ( 'Invalid amount format' ) ;
128- } else if ( value . isLessThan ( 0 ) ) {
156+ }
157+ if ( value . isLessThan ( 0 ) ) {
129158 throw new BuildTransactionError ( 'Value cannot be less than zero' ) ;
130159 }
131160 }
132161
133- /** @inheritdoc */
162+ /**
163+ * Validates that a raw transaction string is properly formatted.
164+ * @throws ParseTransactionError if raw transaction is invalid
165+ */
134166 validateRawTransaction ( rawTransaction : string ) : void {
135167 if ( ! rawTransaction ) {
136168 throw new ParseTransactionError ( 'Invalid raw transaction: Undefined' ) ;
@@ -141,26 +173,32 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
141173 }
142174
143175 /**
144- * @inheritdoc
145- * */
176+ * Validates a transaction object has all required fields.
177+ * @throws Error if transaction is undefined or has invalid data
178+ */
146179 validateTransaction ( transaction ?: Transaction ) : void {
147180 if ( ! transaction ) {
148181 throw new Error ( 'transaction not defined' ) ;
149182 }
183+
150184 this . validateAddress ( { address : transaction . sender } ) ;
151185 this . validateGasData ( {
152186 gasBudget : transaction . gasBudget ,
153187 gasPrice : transaction . gasPrice ,
154188 gasPaymentObjects : transaction . gasPaymentObjects ,
155189 } ) ;
190+
156191 if ( transaction . gasSponsor ) {
157192 this . validateAddress ( { address : transaction . gasSponsor } ) ;
158193 }
159194 }
160195
161196 /**
162- * @inheritdoc
163- * */
197+ * Creates a transaction object from a raw transaction string or bytes.
198+ * @param rawTransaction - Raw transaction in base64 string or Uint8Array format
199+ * @returns The parsed transaction object
200+ * @throws BuildTransactionError if raw transaction is invalid
201+ */
164202 fromImplementation ( rawTransaction : string | Uint8Array ) : Transaction {
165203 if ( ! utils . isValidRawTransaction ( rawTransaction ) ) {
166204 throw new BuildTransactionError ( 'Invalid transaction' ) ;
@@ -170,32 +208,50 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
170208 }
171209
172210 /**
173- * @inheritdoc
174- * */
211+ * Sign implementation - not supported for IOTA transactions.
212+ * IOTA transactions must be signed externally.
213+ */
175214 protected signImplementation ( key : BaseKey ) : BaseTransaction {
176215 throw new Error ( 'Method not implemented.' ) ;
177216 }
178217
179218 /**
180- * @inheritdoc
181- * */
219+ * Builds the transaction and prepares it for broadcast.
220+ * Automatically switches from simulate to real transaction mode if gas data is present.
221+ */
182222 protected async buildImplementation ( ) : Promise < Transaction > {
183- // If gas data is provided, this is not a simulate transaction
184- if ( this . transaction . gasPrice && this . transaction . gasBudget && this . transaction . gasPaymentObjects ) {
185- this . transaction . isSimulateTx = false ;
186- }
223+ this . updateTransactionMode ( ) ;
187224 await this . transaction . build ( ) ;
188225 this . transaction . addInputsAndOutputs ( ) ;
189226 return this . transaction ;
190227 }
191228
229+ /**
230+ * Updates the transaction mode based on gas data availability.
231+ * Switches to real transaction mode if all gas data is provided.
232+ */
233+ private updateTransactionMode ( ) : void {
234+ const hasCompleteGasData =
235+ this . transaction . gasPrice && this . transaction . gasBudget && this . transaction . gasPaymentObjects ;
236+
237+ if ( hasCompleteGasData ) {
238+ this . transaction . isSimulateTx = false ;
239+ }
240+ }
241+
242+ /**
243+ * Validates gas data values and presence.
244+ * @throws BuildTransactionError if gas data is invalid
245+ */
192246 private validateGasData ( gasData : GasData ) : void {
193247 if ( gasData . gasBudget ) {
194248 this . validateValue ( new BigNumber ( gasData . gasBudget ) ) ;
195249 }
250+
196251 if ( gasData . gasPrice ) {
197252 this . validateValue ( new BigNumber ( gasData . gasPrice ) ) ;
198253 }
254+
199255 if ( gasData . gasPaymentObjects && gasData . gasPaymentObjects . length === 0 ) {
200256 throw new BuildTransactionError ( 'Gas input objects list is empty' ) ;
201257 }
0 commit comments