From 76675383db2cd47899ffc557c6d5211666b9f4db Mon Sep 17 00:00:00 2001 From: khanti42 Date: Wed, 18 Dec 2024 10:46:16 +0100 Subject: [PATCH] fix: hex normalization in getTransactions (#467) * fix: hex normalization in getTransactions * chore: handle comments * chore: handle comment * chore: align the output and input of a txn hash * chore: lint * chore: handle comment * chore: fix comment text * chore: replace with validateAndParseAddress --------- Co-authored-by: stanleyyuen <102275989+stanleyyconsensys@users.noreply.github.com> --- .../starknet-snap/src/__tests__/helper.ts | 15 ++-- .../src/state/transaction-state-manager.ts | 7 +- .../starknet-snap/src/utils/starknetUtils.ts | 8 +-- .../src/utils/transaction.test.ts | 72 +++++++++++++++++++ .../starknet-snap/src/utils/transaction.ts | 5 +- 5 files changed, 92 insertions(+), 15 deletions(-) diff --git a/packages/starknet-snap/src/__tests__/helper.ts b/packages/starknet-snap/src/__tests__/helper.ts index 802e534c..65278361 100644 --- a/packages/starknet-snap/src/__tests__/helper.ts +++ b/packages/starknet-snap/src/__tests__/helper.ts @@ -17,6 +17,7 @@ import { TransactionFinalityStatus, TransactionExecutionStatus, TransactionType, + validateAndParseAddress, } from 'starknet'; import { v4 as uuidv4 } from 'uuid'; @@ -167,9 +168,7 @@ export async function generateAccounts( 0, ); - if (address.length < 66) { - address = address.replace('0x', `0x${'0'.repeat(66 - address.length)}`); - } + address = validateAndParseAddress(address); accounts.push({ addressSalt: pubKey, @@ -421,7 +420,7 @@ export function generateInvokeTransaction({ * @returns A transaction hash. * */ export function getTransactionHash(base = SixtyThreeHexInBigInt) { - return `0x` + base.toString(16); + return `0x0` + base.toString(16); } export function generateTransactionRequests({ @@ -525,7 +524,9 @@ export function generateStarkScanTransactions({ newTx.sender_address = address; newTx.account_calls[0].caller_address = address; newTx.timestamp = transactionStartFrom; - newTx.transaction_hash = `0x${transactionStartFrom.toString(16)}`; + newTx.transaction_hash = validateAndParseAddress( + `0x${transactionStartFrom.toString(16)}`, + ); transactionStartFrom -= timestampReduction; txs.push(newTx as unknown as StarkScanTransaction); } @@ -536,7 +537,9 @@ export function generateStarkScanTransactions({ account_calls: [...cairo0DeployTx.account_calls], }; deployTx.contract_address = address; - deployTx.transaction_hash = `0x${transactionStartFrom.toString(16)}`; + deployTx.transaction_hash = validateAndParseAddress( + `0x${transactionStartFrom.toString(16)}`, + ); txs.push(deployTx as unknown as StarkScanTransaction); } diff --git a/packages/starknet-snap/src/state/transaction-state-manager.ts b/packages/starknet-snap/src/state/transaction-state-manager.ts index 0973ce82..4bf1c316 100644 --- a/packages/starknet-snap/src/state/transaction-state-manager.ts +++ b/packages/starknet-snap/src/state/transaction-state-manager.ts @@ -2,6 +2,7 @@ import type { constants, TransactionType } from 'starknet'; import { TransactionFinalityStatus, TransactionExecutionStatus, + validateAndParseAddress, } from 'starknet'; import { assert, enums, number } from 'superstruct'; @@ -307,7 +308,11 @@ export class TransactionStateManager extends StateManager { if (dataInState) { throw new Error(`Transaction already exist`); } - state.transactions.push(data); + state.transactions.push({ + ...data, + // safe-guard to ensure the txnHash is converted to the expected format + txnHash: validateAndParseAddress(data.txnHash), + }); }); } catch (error) { throw new StateManagerError(error.message); diff --git a/packages/starknet-snap/src/utils/starknetUtils.ts b/packages/starknet-snap/src/utils/starknetUtils.ts index 4002d25c..d0137136 100644 --- a/packages/starknet-snap/src/utils/starknetUtils.ts +++ b/packages/starknet-snap/src/utils/starknetUtils.ts @@ -708,9 +708,7 @@ export const getAccContractAddressAndCallData = (publicKey) => { 0, ); - if (address.length < 66) { - address = address.replace('0x', `0x${'0'.repeat(66 - address.length)}`); - } + address = _validateAndParseAddress(address); return { address, callData, @@ -733,9 +731,7 @@ export const getAccContractAddressAndCallDataLegacy = (publicKey) => { callData, 0, ); - if (address.length < 66) { - address = address.replace('0x', `0x${'0'.repeat(66 - address.length)}`); - } + address = _validateAndParseAddress(address); return { address, callData, diff --git a/packages/starknet-snap/src/utils/transaction.test.ts b/packages/starknet-snap/src/utils/transaction.test.ts index 768bfa24..7f8cdfcc 100644 --- a/packages/starknet-snap/src/utils/transaction.test.ts +++ b/packages/starknet-snap/src/utils/transaction.test.ts @@ -240,6 +240,44 @@ describe('newInvokeTransaction', () => { accountCalls: callsToTranscationAccountCalls(calls), }); }); + + it('convert a 62 transaction hash to 66 transaction hash', async () => { + const chainId = constants.StarknetChainId.SN_SEPOLIA; + const [{ address: senderAddress }] = await generateAccounts(chainId, 1); + const { calls } = callsExamples.multipleCalls; + const txnVersion = 1; + const maxFee = '10'; + + const result = newInvokeTransaction({ + // 62 transaction hash + txnHash: + '0xb28a089e7fb83debee4607b6334d687918644796b47d9e9e38ea8213833137', + senderAddress, + chainId, + maxFee, + calls, + txnVersion, + }); + + expect(result).toStrictEqual({ + // 64 transaction hash + txnHash: + '0x00b28a089e7fb83debee4607b6334d687918644796b47d9e9e38ea8213833137', + txnType: TransactionType.INVOKE, + chainId, + senderAddress, + contractAddress: '', + finalityStatus: TransactionFinalityStatus.RECEIVED, + executionStatus: TransactionFinalityStatus.RECEIVED, + failureReason: '', + timestamp: expect.any(Number), + dataVersion: TransactionDataVersion.V2, + version: txnVersion, + maxFee, + actualFee: null, + accountCalls: callsToTranscationAccountCalls(calls), + }); + }); }); describe('newDeployTransaction', () => { @@ -273,4 +311,38 @@ describe('newDeployTransaction', () => { accountCalls: null, }); }); + + it('convert a 62 transaction hash to 66 transaction hash', async () => { + const chainId = constants.StarknetChainId.SN_SEPOLIA; + const [{ address: senderAddress }] = await generateAccounts(chainId, 1); + const txnVersion = 1; + + const result = newDeployTransaction({ + // 62 transaction hash + txnHash: + '0xb28a089e7fb83debee4607b6334d687918644796b47d9e9e38ea8213833137', + senderAddress, + chainId, + txnVersion, + }); + + expect(result).toStrictEqual({ + // 64 transaction hash + txnHash: + '0x00b28a089e7fb83debee4607b6334d687918644796b47d9e9e38ea8213833137', + txnType: TransactionType.DEPLOY_ACCOUNT, + chainId, + senderAddress, + contractAddress: senderAddress, + finalityStatus: TransactionFinalityStatus.RECEIVED, + executionStatus: TransactionFinalityStatus.RECEIVED, + failureReason: '', + timestamp: expect.any(Number), + dataVersion: TransactionDataVersion.V2, + version: txnVersion, + maxFee: null, + actualFee: null, + accountCalls: null, + }); + }); }); diff --git a/packages/starknet-snap/src/utils/transaction.ts b/packages/starknet-snap/src/utils/transaction.ts index 4430fc8f..cdd4590b 100644 --- a/packages/starknet-snap/src/utils/transaction.ts +++ b/packages/starknet-snap/src/utils/transaction.ts @@ -3,6 +3,7 @@ import { constants, TransactionFinalityStatus, TransactionType, + validateAndParseAddress, } from 'starknet'; import { FeeToken } from '../types/snapApi'; @@ -155,7 +156,7 @@ export function newInvokeTransaction({ txnVersion: number; }): V2Transaction { return { - txnHash, + txnHash: validateAndParseAddress(txnHash), txnType: TransactionType.INVOKE, chainId, senderAddress, @@ -196,7 +197,7 @@ export function newDeployTransaction({ txnVersion: number; }): V2Transaction { return { - txnHash, + txnHash: validateAndParseAddress(txnHash), txnType: TransactionType.DEPLOY_ACCOUNT, chainId, senderAddress,