From 76b6ab49f6721d1f76c3f30d3d88d6dbc8b80bda Mon Sep 17 00:00:00 2001 From: Toni Tabak Date: Tue, 12 Dec 2023 08:57:29 +0100 Subject: [PATCH] fix: provider rpc 0.5-0.6 getTransactionReceipt response standardization --- __tests__/account.test.ts | 4 +- __tests__/schemas/provider.json | 11 +- src/provider/rpc.ts | 4 +- src/types/api/rpcspec_0_6/nonspec.ts | 4 + src/types/provider/configuration.ts | 17 --- src/types/provider/response.ts | 6 +- src/utils/responseParser/rpc.ts | 17 +++ src/utils/responseParser/sequencer.ts | 210 -------------------------- 8 files changed, 40 insertions(+), 233 deletions(-) delete mode 100644 src/utils/responseParser/sequencer.ts diff --git a/__tests__/account.test.ts b/__tests__/account.test.ts index 5d2c29a53..460b2c1d4 100644 --- a/__tests__/account.test.ts +++ b/__tests__/account.test.ts @@ -96,7 +96,9 @@ describe('deploy and test Wallet', () => { }); expect(result).toMatchSchemaRef('EstimateFee'); - expect(innerInvokeEstFeeSpy.mock.calls[0][1].version).toBe(constants.TRANSACTION_VERSION.F1); + expect([constants.TRANSACTION_VERSION.F1, constants.TRANSACTION_VERSION.F3]).toContain( + innerInvokeEstFeeSpy.mock.calls[0][1].version + ); innerInvokeEstFeeSpy.mockClear(); }); diff --git a/__tests__/schemas/provider.json b/__tests__/schemas/provider.json index 486836dab..cff283f84 100644 --- a/__tests__/schemas/provider.json +++ b/__tests__/schemas/provider.json @@ -203,7 +203,16 @@ ] }, "actual_fee": { - "type": "string" + "type": "object", + "properties": { + "amount": { + "type": "string" + }, + "unit": { + "type": "string", + "enum": ["WEI", "FRI"] + } + } }, "status_data": { "type": "string" diff --git a/src/provider/rpc.ts b/src/provider/rpc.ts index c8195557a..c33dc10ed 100644 --- a/src/provider/rpc.ts +++ b/src/provider/rpc.ts @@ -127,7 +127,9 @@ export class RpcProvider implements ProviderInterface { } public async getTransactionReceipt(txHash: BigNumberish) { - return this.channel.getTransactionReceipt(txHash); + return this.channel + .getTransactionReceipt(txHash) + .then(this.responseParser.parseTransactionReceipt); } public async getTransactionTrace(txHash: BigNumberish) { diff --git a/src/types/api/rpcspec_0_6/nonspec.ts b/src/types/api/rpcspec_0_6/nonspec.ts index 55a9d732b..251f1e201 100644 --- a/src/types/api/rpcspec_0_6/nonspec.ts +++ b/src/types/api/rpcspec_0_6/nonspec.ts @@ -15,6 +15,7 @@ import { EVENTS_CHUNK, EVENT_FILTER, FEE_ESTIMATE, + FEE_PAYMENT, FELT, MSG_FROM_L1, NONCE_UPDATE, @@ -22,6 +23,7 @@ import { PENDING_BLOCK_WITH_TX_HASHES, PENDING_STATE_UPDATE, PENDING_TXN_RECEIPT, + PRICE_UNIT, REPLACED_CLASS, RESOURCE_BOUNDS_MAPPING, RESULT_PAGE_REQUEST, @@ -88,6 +90,8 @@ export type TransactionStatus = { execution_status?: TXN_EXECUTION_STATUS; }; export type ResourceBounds = RESOURCE_BOUNDS_MAPPING; +export type FeePayment = FEE_PAYMENT; +export type PriceUnit = PRICE_UNIT; // Diff Than Seq export type StorageDiffs = Array; diff --git a/src/types/provider/configuration.ts b/src/types/provider/configuration.ts index a4e067b07..b4d614f6d 100644 --- a/src/types/provider/configuration.ts +++ b/src/types/provider/configuration.ts @@ -12,20 +12,3 @@ export type RpcProviderOptions = { default?: boolean; waitMode?: boolean; }; - -export type SequencerHttpMethod = 'POST' | 'GET'; - -export type SequencerProviderOptions = { - headers?: Record; - blockIdentifier?: BlockIdentifier; - chainId?: StarknetChainId; -} & ( - | { - network: NetworkName | StarknetChainId; - } - | { - baseUrl: string; - feederGatewayUrl?: string; - gatewayUrl?: string; - } -); diff --git a/src/types/provider/response.ts b/src/types/provider/response.ts index 848ce2745..41dc39790 100644 --- a/src/types/provider/response.ts +++ b/src/types/provider/response.ts @@ -112,7 +112,7 @@ export interface InvokeTransactionReceiptResponse { execution_status: TransactionExecutionStatus; finality_status: TransactionFinalityStatus; status?: `${TransactionStatus}`; // SEQ only - actual_fee: string | RPC.SPEC.FEE_ESTIMATE; + actual_fee: RPC.FeePayment; block_hash: RPC.BlockHash; block_number: BlockNumber; transaction_hash: string; @@ -127,7 +127,7 @@ export type DeclareTransactionReceiptResponse = { execution_status: TransactionExecutionStatus; finality_status: TransactionFinalityStatus; status?: `${TransactionStatus}`; // SEQ only - actual_fee: string; + actual_fee: RPC.FeePayment; block_hash: RPC.BlockHash; block_number: BlockNumber; transaction_hash: string; @@ -157,7 +157,7 @@ export type RevertedTransactionReceiptResponse = { execution_status: TransactionExecutionStatus.REVERTED | any; // any due to RPC Spec issue finality_status: TransactionFinalityStatus | any; status?: TransactionStatus; // SEQ only - actual_fee: string | RPC.SPEC.FEE_PAYMENT; + actual_fee: RPC.FeePayment; block_hash?: string; // ?~ optional due to RPC spec issue block_number?: BlockNumber; // ?~ optional due to RCP spec issue transaction_hash: string; diff --git a/src/utils/responseParser/rpc.ts b/src/utils/responseParser/rpc.ts index 292ad4824..363a840ae 100644 --- a/src/utils/responseParser/rpc.ts +++ b/src/utils/responseParser/rpc.ts @@ -9,7 +9,9 @@ import { EstimateFeeResponse, EstimateFeeResponseBulk, GetBlockResponse, + GetTransactionReceiptResponse, GetTransactionResponse, + RPC, SimulateTransactionResponse, } from '../../types'; import { @@ -45,6 +47,21 @@ export class RPCResponseParser }; } + public parseTransactionReceipt(res: RPC.TransactionReceipt): GetTransactionReceiptResponse { + if (typeof res.actual_fee === 'string') { + // This case is RPC 0.5. It can be only v2 thx with FRI units + return { + ...res, + actual_fee: { + amount: res.actual_fee, + unit: 'FRI' as RPC.PriceUnit, + }, + }; + } + + return res; + } + public parseGetTransactionResponse(res: TransactionWithHash): GetTransactionResponse { return { calldata: 'calldata' in res ? res.calldata : [], diff --git a/src/utils/responseParser/sequencer.ts b/src/utils/responseParser/sequencer.ts deleted file mode 100644 index 360cd1a22..000000000 --- a/src/utils/responseParser/sequencer.ts +++ /dev/null @@ -1,210 +0,0 @@ -/** - * Map Sequencer Response to common interface response - * Intersection (sequencer response ∩ (∪ rpc responses)) - */ - -import { LibraryError } from '../../provider/errors'; -import { - CallContractResponse, - CompiledContract, - ContractClassResponse, - DeclareContractResponse, - DeployContractResponse, - EstimateFeeResponse, - EstimateFeeResponseBulk, - GetBlockResponse, - GetTransactionReceiptResponse, - GetTransactionResponse, - HexCalldata, - InvokeFunctionResponse, - Sequencer, - SimulateTransactionResponse, - StateUpdateResponse, - TransactionFinalityStatus, - TransactionStatus, -} from '../../types'; -import { isSierra } from '../contract'; -import { toBigInt } from '../num'; -import { parseContract } from '../provider'; -import { estimatedFeeToMaxFee } from '../stark'; -import { ResponseParser } from '.'; - -export class SequencerAPIResponseParser extends ResponseParser { - public parseGetBlockResponse(res: Sequencer.GetBlockResponse): GetBlockResponse { - return { - ...res, - new_root: res.state_root, - parent_hash: res.parent_block_hash, - transactions: Object.values(res.transactions) - .map((value) => 'transaction_hash' in value && value.transaction_hash) - .filter(Boolean) as Array, - }; - } - - public parseGetTransactionResponse( - res: Sequencer.GetTransactionResponse - ): GetTransactionResponse { - if ( - res.status === TransactionStatus.NOT_RECEIVED && - res.finality_status === TransactionFinalityStatus.NOT_RECEIVED - ) { - throw new LibraryError(); - } - - return { - ...res, - calldata: 'calldata' in res.transaction ? (res.transaction.calldata as HexCalldata) : [], - contract_class: - 'contract_class' in res.transaction ? (res.transaction.contract_class as any) : undefined, - entry_point_selector: - 'entry_point_selector' in res.transaction - ? res.transaction.entry_point_selector - : undefined, - max_fee: 'max_fee' in res.transaction ? (res.transaction.max_fee as string) : undefined, - nonce: res.transaction.nonce as string, - sender_address: - 'sender_address' in res.transaction - ? (res.transaction.sender_address as string) - : undefined, - signature: 'signature' in res.transaction ? res.transaction.signature : undefined, - transaction_hash: - 'transaction_hash' in res.transaction ? res.transaction.transaction_hash : undefined, - version: 'version' in res.transaction ? (res.transaction.version as string) : undefined, - }; - } - - public parseGetTransactionReceiptResponse( - res: Sequencer.TransactionReceiptResponse - ): GetTransactionReceiptResponse { - return { - ...res, - messages_sent: res.l2_to_l1_messages as any, - ...('revert_error' in res && { revert_reason: res.revert_error }), - }; - } - - public parseFeeEstimateResponse(res: Sequencer.EstimateFeeResponse): EstimateFeeResponse { - if ('overall_fee' in res) { - let gasInfo = {}; - - try { - gasInfo = { - gas_consumed: toBigInt(res.gas_usage), - gas_price: toBigInt(res.gas_price), - }; - } catch { - // do nothing - } - - return { - overall_fee: toBigInt(res.overall_fee), - ...gasInfo, - }; - } - return { - overall_fee: toBigInt(res.amount), - }; - } - - public parseFeeEstimateBulkResponse( - res: Sequencer.EstimateFeeResponseBulk - ): EstimateFeeResponseBulk { - return [].concat(res as []).map((item: Sequencer.EstimateFeeResponse) => { - if ('overall_fee' in item) { - let gasInfo = {}; - - try { - gasInfo = { - gas_consumed: toBigInt(item.gas_usage), - gas_price: toBigInt(item.gas_price), - }; - } catch { - // do nothing - } - - return { - overall_fee: toBigInt(item.overall_fee), - ...gasInfo, - }; - } - return { - overall_fee: toBigInt(item.amount), - }; - }); - } - - public parseSimulateTransactionResponse( - res: Sequencer.SimulateTransactionResponse - ): SimulateTransactionResponse { - const suggestedMaxFee = - 'overall_fee' in res.fee_estimation - ? res.fee_estimation.overall_fee - : res.fee_estimation.amount; - return [ - { - transaction_trace: res.trace, - fee_estimation: res.fee_estimation, - suggestedMaxFee: estimatedFeeToMaxFee(BigInt(suggestedMaxFee)), - }, - ]; - } - - public parseCallContractResponse(res: Sequencer.CallContractResponse): CallContractResponse { - return { - result: res.result, - }; - } - - public parseInvokeFunctionResponse( - res: Sequencer.AddTransactionResponse - ): InvokeFunctionResponse { - return { - transaction_hash: res.transaction_hash, - }; - } - - public parseDeployContractResponse( - res: Sequencer.AddTransactionResponse - ): DeployContractResponse { - return { - transaction_hash: res.transaction_hash, - contract_address: res.address as string, - }; - } - - public parseDeclareContractResponse( - res: Sequencer.AddTransactionResponse - ): DeclareContractResponse { - return { - transaction_hash: res.transaction_hash, - class_hash: res.class_hash as string, - }; - } - - public parseGetStateUpdateResponse(res: Sequencer.StateUpdateResponse): StateUpdateResponse { - const nonces = Object.entries(res.state_diff.nonces).map(([contract_address, nonce]) => ({ - contract_address, - nonce, - })); - const storage_diffs = Object.entries(res.state_diff.storage_diffs).map( - ([address, storage_entries]) => ({ address, storage_entries }) - ); - - return { - ...res, - state_diff: { - ...res.state_diff, - storage_diffs, - nonces, - }, - }; - } - - public parseContractClassResponse(res: CompiledContract): ContractClassResponse { - const response = isSierra(res) ? res : parseContract(res); - return { - ...response, - abi: typeof response.abi === 'string' ? JSON.parse(response.abi) : response.abi, - }; - } -}