Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions modules/sdk-coin-tempo/src/lib/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,18 +82,25 @@ export class Tip20Transaction extends BaseTransaction {
}

/**
* Build base RLP data array per Tempo EIP-7702 specification
* @param callsTuples Encoded calls
* @param accessTuples Encoded access list
* @returns RLP-ready array of transaction fields
* Convert bigint to hex string for RLP encoding
* @param value bigint value to convert
* @returns Hex string
* @private
*/
private bigintToHex(value: bigint): string {
if (value === 0n) {
return '0x';
}
const hex = value.toString(16);
return '0x' + (hex.length % 2 ? '0' : '') + hex;
}

private buildBaseRlpData(callsTuples: any[], accessTuples: any[]): any[] {
return [
ethers.utils.hexlify(this.txRequest.chainId),
this.txRequest.maxPriorityFeePerGas ? ethers.utils.hexlify(this.txRequest.maxPriorityFeePerGas.toString()) : '0x',
ethers.utils.hexlify(this.txRequest.maxFeePerGas.toString()),
ethers.utils.hexlify(this.txRequest.gas.toString()),
this.txRequest.maxPriorityFeePerGas ? this.bigintToHex(this.txRequest.maxPriorityFeePerGas) : '0x',
this.bigintToHex(this.txRequest.maxFeePerGas),
this.bigintToHex(this.txRequest.gas),
callsTuples,
accessTuples,
'0x', // nonceKey (reserved for 2D nonce system)
Expand Down
46 changes: 44 additions & 2 deletions modules/sdk-coin-tempo/src/lib/transactionBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,13 @@ export class Tip20TransactionBuilder extends AbstractTransactionBuilder {
}

/**
* Build the transaction from configured TIP-20 operations and transaction parameters
* Validate the transaction has all required fields for Tempo AA transactions.
* Overrides parent class validation since AA transactions use a different model
* (operations-based rather than single contract address).
*
* @throws BuildTransactionError if validation fails
*/
protected async buildImplementation(): Promise<BaseTransaction> {
validateTransaction(): void {
if (this.operations.length === 0) {
throw new BuildTransactionError('At least one operation is required to build a transaction');
}
Expand All @@ -68,6 +72,24 @@ export class Tip20TransactionBuilder extends AbstractTransactionBuilder {
if (this._maxPriorityFeePerGas === undefined) {
throw new BuildTransactionError('maxPriorityFeePerGas is required to build a transaction');
}
}

/**
* Build the transaction from configured TIP-20 operations and transaction parameters.
* Validation is performed by validateTransaction() which is called by build() before this method.
*/
protected async buildImplementation(): Promise<BaseTransaction> {
// These checks satisfy TypeScript's type narrowing.
// validateTransaction() already ensures these are defined, but TypeScript
// doesn't track that across method boundaries.
if (
this._nonce === undefined ||
this._gas === undefined ||
this._maxFeePerGas === undefined ||
this._maxPriorityFeePerGas === undefined
) {
throw new BuildTransactionError('Transaction validation failed: missing required fields');
}

const calls = this.operations.map((op) => this.operationToCall(op));

Expand Down Expand Up @@ -140,6 +162,7 @@ export class Tip20TransactionBuilder extends AbstractTransactionBuilder {
throw new BuildTransactionError(`Invalid gas limit: ${gas}`);
}
this._gas = gasValue;
this.updateEip1559Fee();
return this;
}

Expand All @@ -155,6 +178,7 @@ export class Tip20TransactionBuilder extends AbstractTransactionBuilder {
throw new BuildTransactionError(`Invalid maxFeePerGas: ${maxFeePerGas}`);
}
this._maxFeePerGas = feeValue;
this.updateEip1559Fee();
return this;
}

Expand All @@ -170,9 +194,27 @@ export class Tip20TransactionBuilder extends AbstractTransactionBuilder {
throw new BuildTransactionError(`Invalid maxPriorityFeePerGas: ${maxPriorityFeePerGas}`);
}
this._maxPriorityFeePerGas = feeValue;
this.updateEip1559Fee();
return this;
}

/**
* Update the parent class fee structure with EIP-1559 parameters
* @private
*/
private updateEip1559Fee(): void {
if (this._maxFeePerGas !== undefined && this._maxPriorityFeePerGas !== undefined && this._gas !== undefined) {
this.fee({
fee: this._maxFeePerGas.toString(),
gasLimit: this._gas.toString(),
eip1559: {
maxFeePerGas: this._maxFeePerGas.toString(),
maxPriorityFeePerGas: this._maxPriorityFeePerGas.toString(),
},
});
}
}

/**
* Get all operations in this transaction
* @returns Array of TIP-20 operations
Expand Down
Loading