UNPKG

starknet

Version:
1 lines 895 kB
{"version":3,"sources":["../src/global/constants.ts","../src/types/api/index.ts","../src/types/api/jsonrpc/index.ts","../src/utils/encode.ts","../src/global/config.ts","../src/global/logger.type.ts","../src/global/logger.ts","../src/channel/rpc_0_7_1.ts","../src/types/index.ts","../src/types/lib/contract/index.ts","../src/types/lib/index.ts","../src/provider/types/spec.type.ts","../src/types/calldata.ts","../src/types/outsideExecution.ts","../src/types/typedData.ts","../src/utils/json.ts","../src/utils/batch/index.ts","../src/utils/assert.ts","../src/utils/num.ts","../src/utils/typed.ts","../src/utils/hash/selector.ts","../src/utils/shortString.ts","../src/utils/calldata/byteArray.ts","../src/utils/calldata/cairo.ts","../src/utils/cairoDataTypes/felt.ts","../src/utils/cairoDataTypes/uint256.ts","../src/utils/cairoDataTypes/uint512.ts","../src/utils/calldata/enum/CairoCustomEnum.ts","../src/utils/calldata/enum/CairoOption.ts","../src/utils/calldata/enum/CairoResult.ts","../src/utils/calldata/formatter.ts","../src/utils/calldata/parser/parser-0-1.1.0.ts","../src/utils/calldata/parser/parser-2.0.0.ts","../src/utils/calldata/parser/index.ts","../src/utils/calldata/tuple.ts","../src/utils/cairoDataTypes/fixedArray.ts","../src/utils/calldata/propertyOrder.ts","../src/utils/calldata/requestParser.ts","../src/utils/calldata/responseParser.ts","../src/utils/calldata/validate.ts","../src/utils/calldata/index.ts","../src/utils/hash/index.ts","../src/utils/hash/transactionHash/v2.ts","../src/utils/ec.ts","../src/utils/hash/transactionHash/v3.ts","../src/utils/hash/transactionHash/index.ts","../src/utils/hash/classHash.ts","../src/utils/stark/index.ts","../src/utils/resolve.ts","../src/utils/stark/rpc07.ts","../src/utils/stark/rpc08.ts","../src/utils/contract.ts","../src/utils/errors/rpc.ts","../src/utils/errors/index.ts","../src/utils/eth.ts","../src/utils/connect/fetch.ts","../src/utils/provider.ts","../src/utils/transaction.ts","../src/channel/rpc_0_8_1.ts","../src/utils/eventEmitter.ts","../src/utils/connect/ws.ts","../src/channel/ws/subscription.ts","../src/channel/ws/ws_0_8.ts","../src/utils/responseParser/rpc.ts","../src/utils/transactionReceipt/transactionReceipt.ts","../src/utils/typedData.ts","../src/utils/merkle.ts","../src/provider/rpc.ts","../src/provider/extensions/default.ts","../src/utils/starknetId.ts","../src/provider/extensions/starknetId.ts","../src/provider/interface.ts","../src/provider/index.ts","../src/signer/interface.ts","../src/signer/default.ts","../src/signer/ethSigner.ts","../src/utils/uint256.ts","../src/signer/ledgerSigner111.ts","../src/utils/address.ts","../src/signer/ledgerSigner221.ts","../src/signer/ledgerSigner231.ts","../src/utils/events/index.ts","../src/utils/outsideExecution.ts","../src/utils/src5.ts","../src/utils/paymaster.ts","../src/paymaster/rpc.ts","../src/paymaster/interface.ts","../src/paymaster/index.ts","../src/account/default.ts","../src/account/interface.ts","../src/wallet/connect.ts","../src/wallet/account.ts","../src/contract/default.ts","../src/contract/interface.ts","../src/contract/contractFactory.ts","../src/utils/responseParser/interface.ts","../src/utils/units.ts"],"sourcesContent":["/* eslint-disable no-underscore-dangle */\nimport type { FeeMarginPercentage } from '../types';\nimport { ETransactionVersion, RPCSPEC08 } from '../types/api';\nimport { ValuesType } from '../types/helpers/valuesType';\nimport type { LogLevel } from './logger.type';\n\nexport { IS_BROWSER } from '../utils/encode';\n\n/**\n * Cairo Felt support storing max 31 character\n */\nexport const TEXT_TO_FELT_MAX_LEN = 31;\n\n/**\n * Alternatively use directly from api specification\n * types.RPC.ETransactionVersion\n * For BN do BigInt(TRANSACTION_VERSION.*)\n */\nexport const { ETransactionVersion: TRANSACTION_VERSION } = RPCSPEC08;\n\nexport const ZERO = 0n;\nexport const MASK_250 = 2n ** 250n - 1n; // 2 ** 250 - 1\nexport const MASK_31 = 2n ** 31n - 1n; // 2 ** 31 - 1\nexport const API_VERSION = ZERO;\nexport const PRIME = 2n ** 251n + 17n * 2n ** 192n + 1n;\n\n// based on: https://github.com/starkware-libs/cairo-lang/blob/v0.12.3/src/starkware/starknet/common/storage.cairo#L3\nexport const MAX_STORAGE_ITEM_SIZE = 256n;\nexport const ADDR_BOUND = 2n ** 251n - MAX_STORAGE_ITEM_SIZE;\n\nconst range = (min: bigint, max: bigint) => ({ min, max }) as const;\n\nexport const RANGE_FELT = range(ZERO, PRIME - 1n);\nexport const RANGE_I128 = range(-(2n ** 127n), 2n ** 127n - 1n);\nexport const RANGE_U128 = range(ZERO, 2n ** 128n - 1n);\n\nexport const UDC = {\n ADDRESS: '0x041a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf',\n ENTRYPOINT: 'deployContract',\n} as const;\n\nexport const OutsideExecutionCallerAny = '0x414e595f43414c4c4552'; // encodeShortString('ANY_CALLER')\nexport const SNIP9_V1_INTERFACE_ID =\n '0x68cfd18b92d1907b8ba3cc324900277f5a3622099431ea85dd8089255e4181';\nexport const SNIP9_V2_INTERFACE_ID =\n '0x1d1144bb2138366ff28d8e9ab57456b1d332ac42196230c3a602003c89872';\n\n// Ledger signer\n// 0x80\nexport const HARDENING_BYTE = 128;\n// 0x80000000\nexport const HARDENING_4BYTES = 2147483648n;\n\n// NOTE: the enum alias exports are made so both the 'const' and 'type' are reachable in the published '.d.ts' file,\n// otherwise the last export hides the preceding export with the same name in this file\nconst _BaseUrl = {\n SN_MAIN: 'https://alpha-mainnet.starknet.io',\n SN_SEPOLIA: 'https://alpha-sepolia.starknet.io',\n} as const;\ntype _BaseUrl = ValuesType<typeof _BaseUrl>;\nexport { _BaseUrl as BaseUrl };\n\nconst _NetworkName = {\n SN_MAIN: 'SN_MAIN',\n SN_SEPOLIA: 'SN_SEPOLIA',\n} as const;\ntype _NetworkName = ValuesType<typeof _NetworkName>;\nexport { _NetworkName as NetworkName };\n\nconst _StarknetChainId = {\n SN_MAIN: '0x534e5f4d41494e', // encodeShortString('SN_MAIN'),\n SN_SEPOLIA: '0x534e5f5345504f4c4941', // encodeShortString('SN_SEPOLIA')\n} as const;\ntype _StarknetChainId = ValuesType<typeof _StarknetChainId>;\nexport { _StarknetChainId as StarknetChainId };\n\nconst _TransactionHashPrefix = {\n DECLARE: '0x6465636c617265', // encodeShortString('declare'),\n DEPLOY: '0x6465706c6f79', // encodeShortString('deploy'),\n DEPLOY_ACCOUNT: '0x6465706c6f795f6163636f756e74', // encodeShortString('deploy_account'),\n INVOKE: '0x696e766f6b65', // encodeShortString('invoke'),\n L1_HANDLER: '0x6c315f68616e646c6572', // encodeShortString('l1_handler'),\n} as const;\ntype _TransactionHashPrefix = ValuesType<typeof _TransactionHashPrefix>;\nexport { _TransactionHashPrefix as TransactionHashPrefix };\n\n/**\n * dot format rpc versions\n */\nconst _SupportedRpcVersion = {\n '0.7.1': '0.7.1',\n '0.8.1': '0.8.1',\n v0_7_1: '0.7.1',\n v0_8_1: '0.8.1',\n} as const;\ntype _SupportedRpcVersion = ValuesType<typeof _SupportedRpcVersion>;\nexport { _SupportedRpcVersion as SupportedRpcVersion };\n\nexport type SupportedTransactionVersion =\n | typeof ETransactionVersion.V2\n | typeof ETransactionVersion.V3;\n\n// Default initial global config\nexport const DEFAULT_GLOBAL_CONFIG: {\n legacyMode: boolean;\n logLevel: LogLevel;\n rpcVersion: _SupportedRpcVersion;\n transactionVersion: SupportedTransactionVersion;\n feeMarginPercentage: FeeMarginPercentage;\n fetch: any;\n websocket: any;\n} = {\n legacyMode: false,\n rpcVersion: '0.8.1',\n transactionVersion: ETransactionVersion.V3,\n logLevel: 'INFO',\n feeMarginPercentage: {\n bounds: {\n l1_gas: {\n max_amount: 50,\n max_price_per_unit: 50,\n },\n l1_data_gas: {\n max_amount: 50,\n max_price_per_unit: 50,\n },\n l2_gas: {\n max_amount: 50,\n max_price_per_unit: 50,\n },\n },\n maxFee: 50,\n },\n fetch: undefined,\n websocket: undefined,\n};\n\nexport const RPC_DEFAULT_NODES = {\n SN_MAIN: [`https://starknet-mainnet.public.blastapi.io/rpc/`],\n SN_SEPOLIA: [`https://starknet-sepolia.public.blastapi.io/rpc/`],\n} as const;\n\nexport const PAYMASTER_RPC_NODES = {\n SN_MAIN: [`https://starknet.paymaster.avnu.fi`],\n SN_SEPOLIA: [`https://sepolia.paymaster.avnu.fi`],\n} as const;\n\n// Default system messages\nexport const SYSTEM_MESSAGES = {\n legacyTxWarningMessage:\n 'You are using a deprecated transaction version (V0,V1,V2)!\\nUpdate to the latest V3 transactions!',\n legacyTxRPC08Message: 'RPC 0.8 do not support legacy transactions',\n SWOldV3: 'RPC 0.7 V3 tx (improper resource bounds) not supported in RPC 0.8',\n channelVersionMismatch:\n 'Channel specification version is not compatible with the connected node Specification Version',\n unsupportedSpecVersion:\n 'The connected node specification version is not supported by this library',\n maxFeeInV3: 'maxFee is not supported in V3 transactions, use resourceBounds instead',\n};\n","export * as JRPC from './jsonrpc';\n\nexport * as RPCSPEC07 from '@starknet-io/starknet-types-07';\nexport * as RPCSPEC08 from '@starknet-io/starknet-types-08';\nexport { PAYMASTER_API } from '@starknet-io/starknet-types-08';\n\nexport * from '@starknet-io/starknet-types-08';\n// TODO: Should this be default export type as RPCSPEC07 & RPCSPEC08 are sued only in channel rest of the code do not know what rpc version it works with and it can be both.\n// export * from '../../provider/types/spec.type';\n","export type RequestBody = {\n id: number | string;\n jsonrpc: '2.0';\n method: string;\n params?: {};\n};\n\nexport type ResponseBody = {\n id: number | string;\n jsonrpc: '2.0';\n} & (SuccessResponseBody | ErrorResponseBody);\n\nexport type SuccessResponseBody = {\n result: unknown;\n};\n\nexport type ErrorResponseBody = {\n error: Error;\n};\n\nexport type Error = {\n code: number;\n message: string;\n data?: unknown;\n};\n\nexport type WebSocketEvent = Omit<RequestBody, 'id'> & { params: {} };\n","import { base64 } from '@scure/base';\n\nexport const IS_BROWSER = typeof window !== 'undefined';\n\nconst STRING_ZERO = '0';\n\n/**\n * Some functions recreated from https://github.com/pedrouid/enc-utils/blob/master/src/index.ts\n * enc-utils is not a dependency to avoid using `Buffer` which only works in node and not browsers\n */\n\n/**\n * Convert array buffer to string\n *\n * *[internal usage]*\n *\n * @param {ArrayBuffer} array The ArrayBuffer to convert to string.\n * @returns {string} The converted string.\n *\n * @example\n * ```typescript\n * const buffer = new ArrayBuffer(5);\n * const view = new Uint8Array(buffer);\n * [72, 101, 108, 108, 111].forEach((x, idx) => view[idx] = x);\n * const result = encode.arrayBufferToString(buffer);\n * // result = \"Hello\"\n * ```\n */\nexport function arrayBufferToString(array: ArrayBuffer): string {\n return new Uint8Array(array).reduce((data, byte) => data + String.fromCharCode(byte), '');\n}\n\n/**\n * Convert utf8-string to Uint8Array\n *\n * *[internal usage]*\n *\n * @param {string} str The UTF-8 string to convert.\n * @returns {Uint8Array} The encoded Uint8Array.\n *\n * @example\n * ```typescript\n * const myString = 'Hi';\n * const result = encode.utf8ToArray(myString);\n * // result = Uint8Array(2) [ 72, 105 ]\n * ```\n */\nexport function utf8ToArray(str: string): Uint8Array {\n return new TextEncoder().encode(str);\n}\n\n/**\n * Convert string to array buffer (browser and node compatible)\n *\n * @param {string} a The Base64 encoded string to convert.\n * @returns {Uint8Array} The decoded Uint8Array.\n *\n * @example\n * ```typescript\n * const base64String = 'SGVsbG8='; // 'Hello' in Base64\n * const result = encode.atobUniversal(base64String);\n * // result = Uint8Array(5) [ 72, 101, 108, 108, 111 ]\n * ```\n */\nexport function atobUniversal(a: string): Uint8Array {\n return base64.decode(a);\n}\n\n/**\n * Convert array buffer to string (browser and node compatible)\n *\n * @param {ArrayBuffer} b The Array buffer.\n * @returns {string} The Base64 encoded string.\n *\n * @example\n * ```typescript\n * const buffer = new Uint8Array([72, 101, 108, 108, 111]); // Array with ASCII values for 'Hello'\n * const result = encode.btoaUniversal(buffer);\n * // result = \"SGVsbG8=\"\n * ```\n */\nexport function btoaUniversal(b: ArrayBuffer): string {\n return base64.encode(new Uint8Array(b));\n}\n\n/**\n * Convert array buffer to hex-string\n *\n * @param {Uint8Array} buffer The encoded Uint8Array.\n * @returns {string} The hex-string\n *\n * @example\n * ```typescript\n * const buffer = new Uint8Array([72, 101, 108, 108, 111]); // Array with ASCII values for 'Hello'\n * const result = encode.buf2hex(buffer);\n * // result = \"48656c6c6f\"\n * ```\n */\nexport function buf2hex(buffer: Uint8Array): string {\n return buffer.reduce((r, x) => r + x.toString(16).padStart(2, '0'), '');\n}\n\n/**\n * Remove hex prefix '0x' from hex-string\n * @param hex hex-string\n * @returns {string} The hex-string\n *\n * @example\n * ```typescript\n * const hexStringWithPrefix = '0x48656c6c6f';\n * const result = encode.removeHexPrefix(hexStringWithPrefix);\n * // result: \"48656c6c6f\"\n * ```\n */\nexport function removeHexPrefix(hex: string): string {\n return hex.replace(/^0x/i, '');\n}\n\n/**\n * Add hex prefix '0x' to base16-string\n * @param hex base16-string\n * @returns {string} The hex-string\n *\n * @example\n * ```typescript\n * const plainHexString = '48656c6c6f';\n * const result = encode.addHexPrefix(plainHexString);\n * // result: \"0x48656c6c6f\"\n * ```\n */\nexport function addHexPrefix(hex: string): string {\n return `0x${removeHexPrefix(hex)}`;\n}\n\n/**\n * Prepend or append to string\n *\n * *[internal usage]*\n *\n * Pads a string to a certain length with a specific string.\n * The padding can be applied either to the left or the right of the input string.\n *\n * @param {string} str The string to pad.\n * @param {number} length The target length for the padded string.\n * @param {boolean} left Set to true to add padding to the left, false to add it to the right.\n * @param {string} [padding='0'] The string to use for padding. Defaults to '0'.\n * @returns {string} The padded string.\n *\n * @example\n * ```typescript\n * const myString = 'hello';\n * const result = padString(myString, 10, true);\n * // result = '00000hello'\n * ```\n */\nfunction padString(\n str: string,\n length: number,\n left: boolean,\n padding: string = STRING_ZERO\n): string {\n const diff = length - str.length;\n let result = str;\n if (diff > 0) {\n const pad = padding.repeat(diff);\n result = left ? pad + str : str + pad;\n }\n return result;\n}\n\n/**\n * Prepend string (default with '0')\n *\n * Pads a string to a certain length with a specific string.\n * The padding can be applied only to the left of the input string.\n *\n * @param {string} str The string to pad.\n * @param {number} length The target length for the padded string.\n * @param {string} [padding='0'] The string to use for padding. Defaults to '0'.\n * @returns {string} The padded string.\n * @example\n * ```typescript\n * const myString = '1A3F';\n * const result = encode.padLeft(myString, 10);\n * // result: '0000001A3F'\n * ```\n */\nexport function padLeft(str: string, length: number, padding: string = STRING_ZERO): string {\n return padString(str, length, true, padding);\n}\n\n/**\n * Calculate byte length of string\n *\n * *[no internal usage]*\n *\n * Calculates the byte length of a string based on a specified byte size.\n * The function rounds up the byte count to the nearest multiple of the specified byte size.\n *\n * @param {string} str The string whose byte length is to be calculated.\n * @param {number} [byteSize='8'] The size of the byte block to round up to. Defaults to 8.\n * @returns {number} The calculated byte length, rounded to the nearest multiple of byteSize.\n *\n * @example\n * ```typescript\n * const myString = 'Hello';\n * const result = encode.calcByteLength(myString, 4);\n * // result = 8 (rounded up to the nearest multiple of 4)\n *\n * ```\n */\nexport function calcByteLength(str: string, byteSize: number = 8): number {\n const { length } = str;\n const remainder = length % byteSize;\n return remainder ? ((length - remainder) / byteSize) * byteSize + byteSize : length;\n}\n\n/**\n * Prepend '0' to string bytes\n *\n * *[no internal usage]*\n *\n *\n * * Prepends padding to the left of a string to ensure it matches a specific byte length.\n * The function uses a specified padding character and rounds up the string length to the nearest multiple of `byteSize`.\n *\n * @param {string} str The string to be padded.\n * @param {number} [byteSize='8'] The byte block size to which the string length should be rounded up. Defaults to 8.\n * @param {string} [padding='0'] The character to use for padding. Defaults to '0'.\n * @returns {string} The padded string.\n *\n * @example\n * ```typescript\n * const myString = '123';\n * const result = encode.sanitizeBytes(myString);\n * // result: '00000123' (padded to 8 characters)\n * ```\n */\nexport function sanitizeBytes(\n str: string,\n byteSize: number = 8,\n padding: string = STRING_ZERO\n): string {\n return padLeft(str, calcByteLength(str, byteSize), padding);\n}\n\n/**\n * Sanitizes a hex-string by removing any existing '0x' prefix, padding the string with '0' to ensure it has even length,\n * and then re-adding the '0x' prefix.\n *\n * *[no internal usage]*\n * @param {string} hex hex-string\n * @returns {string} format: hex-string\n *\n * @example\n * ```typescript\n * const unevenHex = '0x23abc';\n * const result = encode.sanitizeHex(unevenHex);\n * // result = '0x023abc' (padded to ensure even length)\n * ```\n */\nexport function sanitizeHex(hex: string): string {\n const hexWithoutPrefix = removeHexPrefix(hex);\n const sanitizedHex = sanitizeBytes(hexWithoutPrefix, 2);\n return sanitizedHex ? addHexPrefix(sanitizedHex) : sanitizedHex;\n}\n\n/**\n * String transformation util\n *\n * Pascal case to screaming snake case\n *\n * @param {string} text The PascalCase string to convert.\n * @returns {string} The converted snake_case string in uppercase.\n *\n * @example\n * ```typescript\n * const pascalString = 'PascalCaseExample';\n * const result = encode.pascalToSnake(pascalString);\n * // result: 'PASCAL_CASE_EXAMPLE'\n * ```\n */\nexport const pascalToSnake = (text: string): string =>\n /[a-z]/.test(text)\n ? text\n .split(/(?=[A-Z])/)\n .join('_')\n .toUpperCase()\n : text;\n\n/**\n * Combine multiple Uint8Arrays into one.\n * Useful for wallet path creation.\n * @param {Uint8Array[]} uint8arrays An array of Uint8Array.\n * @returns {Uint8Array} all the Uint8Arrays joined.\n * @example\n * ```typescript\n * const path0buff = new Uint8Array([128, 0, 10, 85]);\n * const path1buff = new Uint8Array([71, 65, 233, 201]);\n * const result = encode.concatenateArrayBuffer([path0buff, path1buff]);\n * // result = Uint8Array(8) [128, 0, 10, 85, 71, 65, 233, 201]\n * ```\n */\nexport function concatenateArrayBuffer(uint8arrays: Uint8Array[]): Uint8Array {\n const totalLength = uint8arrays.reduce((total, uint8array) => total + uint8array.byteLength, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n uint8arrays.forEach((uint8array) => {\n result.set(uint8array, offset);\n offset += uint8array.byteLength;\n });\n return result;\n}\n","import { DEFAULT_GLOBAL_CONFIG } from './constants';\n\ntype DefaultConfig = typeof DEFAULT_GLOBAL_CONFIG;\ntype CustomConfig = { [key: string]: any };\n\ntype ConfigData = DefaultConfig & CustomConfig;\n\nclass Configuration {\n private static instance: Configuration;\n\n private config!: ConfigData;\n\n private constructor() {\n this.initialize();\n }\n\n private initialize(): void {\n this.config = { ...DEFAULT_GLOBAL_CONFIG };\n }\n\n public static getInstance(): Configuration {\n if (!Configuration.instance) {\n Configuration.instance = new Configuration();\n }\n return Configuration.instance;\n }\n\n public get<K extends keyof DefaultConfig>(key: K): DefaultConfig[K];\n public get(key: string, defaultValue?: any): any;\n public get(key: string, defaultValue?: any) {\n return this.config[key] ?? defaultValue;\n }\n\n public set<K extends keyof DefaultConfig>(key: K, value: DefaultConfig[K]): void;\n public set(key: string, value: any): void;\n public set(key: string, value: any): void {\n this.config[key] = value;\n }\n\n public update(configData: Partial<DefaultConfig> & CustomConfig): void {\n this.config = {\n ...this.config,\n ...configData,\n };\n }\n\n public getAll(): ConfigData {\n return { ...this.config };\n }\n\n public reset(): void {\n this.initialize();\n }\n\n public delete<K extends keyof DefaultConfig>(key: K): void;\n public delete(key: string): void;\n public delete(key: string): void {\n delete this.config[key];\n }\n\n public hasKey<K extends keyof DefaultConfig>(key: K): boolean;\n public hasKey(key: string): boolean;\n public hasKey(key: string): boolean {\n return key in this.config;\n }\n}\n\n// Export a single instance\nexport const config = Configuration.getInstance();\n","import { ValuesType } from '../types/helpers/valuesType';\n\nexport const LogLevelIndex = {\n DEBUG: 5,\n INFO: 4,\n WARN: 3,\n ERROR: 2,\n FATAL: 1,\n OFF: 0,\n};\n\nexport type LogLevelIndex = ValuesType<typeof LogLevelIndex>;\n\nexport type LogLevel = keyof typeof LogLevelIndex;\n","/* eslint-disable no-console */\nimport { config } from './config';\nimport { LogLevelIndex, LogLevel } from './logger.type';\n\ninterface LogMessage {\n level: LogLevel;\n message: string;\n timestamp: string;\n data?: any;\n}\n/**\n * Logging class providing different levels of log\n */\nclass Logger {\n private static instance: Logger;\n\n private config: typeof config;\n\n private constructor() {\n this.config = config;\n }\n\n public static getInstance(): Logger {\n if (!Logger.instance) {\n Logger.instance = new Logger();\n }\n return Logger.instance;\n }\n\n private getTimestamp(): string {\n return new Date().toISOString();\n }\n\n private shouldLog(messageLevel: LogLevelIndex): boolean {\n const configLevel = this.config.get('logLevel', 'INFO');\n return messageLevel <= LogLevelIndex[configLevel as LogLevel];\n }\n\n private formatMessage(logMessage: LogMessage): string {\n const { level, message, timestamp, data } = logMessage;\n let formattedMessage = `[${timestamp}] ${level}: ${message}`;\n\n if (data) {\n try {\n formattedMessage += `\\n${JSON.stringify(data, null, 2)}`;\n } catch (error) {\n formattedMessage += `\\n[JSON.stringify Error/Circular]: ${error}`;\n }\n }\n\n return formattedMessage;\n }\n\n private log(level: LogLevel, message: string, data?: any): void {\n if (!this.shouldLog(LogLevelIndex[level])) {\n return;\n }\n\n const logMessage: LogMessage = {\n level,\n message,\n timestamp: this.getTimestamp(),\n data,\n };\n\n const formattedMessage = this.formatMessage(logMessage);\n\n switch (level) {\n case 'DEBUG':\n console.debug(formattedMessage);\n break;\n case 'INFO':\n console.info(formattedMessage);\n break;\n case 'WARN':\n console.warn(formattedMessage);\n break;\n case 'ERROR':\n case 'FATAL':\n console.error(formattedMessage);\n break;\n case 'OFF':\n // Do nothing when logging is off\n break;\n default:\n console.log(formattedMessage); // Default fallback for unknown log levels\n break;\n }\n }\n\n /**\n * debug will be displayed when LogLevel level is set to DEBUG(5)\n */\n public debug(message: string, data?: any): void {\n this.log('DEBUG', message, data);\n }\n\n /**\n * info will be displayed when LogLevel level is set to DEBUG(5), INFO(4)\n */\n public info(message: string, data?: any): void {\n this.log('INFO', message, data);\n }\n\n /**\n * warn will be displayed when LogLevel level is set to DEBUG(5), INFO(4), WARN(3)\n */\n public warn(message: string, data?: any): void {\n this.log('WARN', message, data);\n }\n\n /**\n * error will be displayed when LogLevel level is set to DEBUG(5), INFO(4), WARN(3), ERROR(2)\n */\n public error(message: string, data?: any): void {\n this.log('ERROR', message, data);\n }\n\n /**\n * fatal will be displayed when LogLevel level is set to DEBUG(5), INFO(4), WARN(3), ERROR(2), FATAL(1)\n */\n public fatal(message: string, data?: any): void {\n this.log('FATAL', message, data);\n }\n\n /**\n * Set the logging level you would like system to display\n * * 5 DEBUG - show all logs\n * * 4 INFO\n * * 3 WARN\n * * 2 ERROR\n * * 1 FATAL\n * * 0 OFF - disable logs\n */\n public setLogLevel(level: LogLevel): void {\n this.config.set('logLevel', level);\n }\n\n public getLogLevel(): LogLevel {\n return this.config.get('logLevel', 'INFO');\n }\n\n /**\n *\n * @returns logs levels displayed on the configured LogLevel\n */\n public getEnabledLogLevels() {\n return Object.keys(LogLevelIndex).filter((s) => {\n return this.shouldLog(LogLevelIndex[s as LogLevel]) && s !== 'OFF';\n });\n }\n}\n\n// Export a single instance\n/**\n * Logger instance, use for the system logging.\n * Higher the logger level index, higher the LogLevel required to display log.\n * Default should be INFO\n *\n * DEBUG: 5,\n * INFO: 4,\n * WARN: 3,\n * ERROR: 2,\n * FATAL: 1,\n */\nexport const logger = Logger.getInstance();\n","import {\n NetworkName,\n StarknetChainId,\n SupportedRpcVersion,\n SYSTEM_MESSAGES,\n} from '../global/constants';\nimport {\n AccountInvocationItem,\n AccountInvocations,\n BigNumberish,\n BlockIdentifier,\n BlockTag,\n Call,\n DeclareContractTransaction,\n DeployAccountContractTransaction,\n getEstimateFeeBulkOptions,\n getSimulateTransactionOptions,\n Invocation,\n InvocationsDetailsWithNonce,\n RPC_ERROR,\n RpcProviderOptions,\n TransactionType,\n waitForTransactionOptions,\n} from '../types';\nimport { JRPC, RPCSPEC07 as RPC } from '../types/api';\nimport { BatchClient } from '../utils/batch';\nimport { CallData } from '../utils/calldata';\nimport { isSierra } from '../utils/contract';\nimport { LibraryError, RpcError } from '../utils/errors';\nimport { validateAndParseEthAddress } from '../utils/eth';\nimport fetch from '../utils/connect/fetch';\nimport { getSelector, getSelectorFromName } from '../utils/hash';\nimport { stringify } from '../utils/json';\nimport { getHexStringArray, toHex, toStorageKey } from '../utils/num';\nimport { Block, getDefaultNodeUrl, wait } from '../utils/provider';\nimport { isSupportedSpecVersion, isV3Tx, isVersion } from '../utils/resolve';\nimport { decompressProgram, signatureToHexArray } from '../utils/stark';\nimport { getVersionsByType } from '../utils/transaction';\nimport { logger } from '../global/logger';\nimport { config } from '../global/config';\nimport { assertX } from '../utils/assert';\n\nconst defaultOptions = {\n headers: { 'Content-Type': 'application/json' },\n blockIdentifier: BlockTag.PENDING,\n retries: 200,\n};\n\nexport class RpcChannel {\n readonly id = 'RPC071';\n\n /**\n * RPC specification version this Channel class implements\n */\n readonly channelSpecVersion: SupportedRpcVersion = SupportedRpcVersion.v0_7_1;\n\n public nodeUrl: string;\n\n public headers: object;\n\n public requestId: number;\n\n readonly blockIdentifier: BlockIdentifier;\n\n readonly retries: number;\n\n readonly waitMode: boolean; // behave like web2 rpc and return when tx is processed\n\n private chainId?: StarknetChainId;\n\n /**\n * RPC specification version of the connected node\n */\n private specVersion?: SupportedRpcVersion;\n\n private transactionRetryIntervalFallback?: number;\n\n private batchClient?: BatchClient;\n\n private baseFetch: NonNullable<RpcProviderOptions['baseFetch']>;\n\n constructor(optionsOrProvider?: RpcProviderOptions) {\n const {\n baseFetch,\n batch,\n blockIdentifier,\n chainId,\n headers,\n nodeUrl,\n retries,\n specVersion,\n transactionRetryIntervalFallback,\n waitMode,\n } = optionsOrProvider || {};\n if (Object.values(NetworkName).includes(nodeUrl as NetworkName)) {\n this.nodeUrl = getDefaultNodeUrl(\n nodeUrl as NetworkName,\n optionsOrProvider?.default,\n this.channelSpecVersion\n );\n } else if (nodeUrl) {\n this.nodeUrl = nodeUrl;\n } else {\n this.nodeUrl = getDefaultNodeUrl(\n undefined,\n optionsOrProvider?.default,\n this.channelSpecVersion\n );\n }\n this.baseFetch = baseFetch || config.get('fetch') || fetch;\n this.blockIdentifier = blockIdentifier ?? defaultOptions.blockIdentifier;\n this.chainId = chainId;\n this.headers = { ...defaultOptions.headers, ...headers };\n this.retries = retries ?? defaultOptions.retries;\n this.specVersion = specVersion;\n this.transactionRetryIntervalFallback = transactionRetryIntervalFallback;\n this.waitMode = waitMode ?? false;\n this.requestId = 0;\n\n if (typeof batch === 'number') {\n this.batchClient = new BatchClient({\n nodeUrl: this.nodeUrl,\n headers: this.headers,\n interval: batch,\n baseFetch: this.baseFetch,\n });\n }\n\n logger.debug('Using Channel', this.id);\n }\n\n public readSpecVersion() {\n return this.specVersion;\n }\n\n private get transactionRetryIntervalDefault() {\n return this.transactionRetryIntervalFallback ?? 5000;\n }\n\n public setChainId(chainId: StarknetChainId) {\n this.chainId = chainId;\n }\n\n public fetch(method: string, params?: object, id: string | number = 0) {\n const rpcRequestBody: JRPC.RequestBody = {\n id,\n jsonrpc: '2.0',\n method,\n ...(params && { params }),\n };\n return this.baseFetch(this.nodeUrl, {\n method: 'POST',\n body: stringify(rpcRequestBody),\n headers: this.headers as Record<string, string>,\n });\n }\n\n protected errorHandler(method: string, params: any, rpcError?: JRPC.Error, otherError?: any) {\n if (rpcError) {\n throw new RpcError(rpcError as RPC_ERROR, method, params);\n }\n if (otherError instanceof LibraryError) {\n throw otherError;\n }\n if (otherError) {\n throw Error(otherError.message);\n }\n }\n\n protected async fetchEndpoint<T extends keyof RPC.Methods>(\n method: T,\n params?: RPC.Methods[T]['params']\n ): Promise<RPC.Methods[T]['result']> {\n try {\n if (this.batchClient) {\n const { error, result } = await this.batchClient.fetch(\n method,\n params as any, // TODO: fix this temporary cast with some permanent solution\n (this.requestId += 1)\n );\n this.errorHandler(method, params, error);\n return result as RPC.Methods[T]['result'];\n }\n\n const rawResult = await this.fetch(method, params, (this.requestId += 1));\n const { error, result } = await rawResult.json();\n this.errorHandler(method, params, error);\n return result as RPC.Methods[T]['result'];\n } catch (error: any) {\n this.errorHandler(method, params, error?.response?.data, error);\n throw error;\n }\n }\n\n public async getChainId() {\n this.chainId ??= (await this.fetchEndpoint('starknet_chainId')) as StarknetChainId;\n return this.chainId;\n }\n\n /**\n * fetch rpc node specVersion\n * @example this.specVersion = \"0.7.1\"\n */\n public getSpecVersion() {\n return this.fetchEndpoint('starknet_specVersion');\n }\n\n /**\n * fetch if undefined test and set specVersion, else just return this.specVersion\n * @example this.specVersion = \"0.7.1\"\n */\n public async setUpSpecVersion() {\n if (!this.specVersion) {\n const unknownSpecVersion = await this.fetchEndpoint('starknet_specVersion');\n\n // check if the channel is compatible with the node\n if (!isVersion(this.channelSpecVersion, unknownSpecVersion)) {\n logger.error(SYSTEM_MESSAGES.channelVersionMismatch, {\n channelId: this.id,\n channelSpecVersion: this.channelSpecVersion,\n nodeSpecVersion: this.specVersion,\n });\n }\n\n if (!isSupportedSpecVersion(unknownSpecVersion)) {\n throw new LibraryError(`${SYSTEM_MESSAGES.unsupportedSpecVersion}, channelId: ${this.id}`);\n }\n\n this.specVersion = unknownSpecVersion;\n }\n return this.specVersion;\n }\n\n public getNonceForAddress(\n contractAddress: BigNumberish,\n blockIdentifier: BlockIdentifier = this.blockIdentifier\n ) {\n const contract_address = toHex(contractAddress);\n const block_id = new Block(blockIdentifier).identifier;\n return this.fetchEndpoint('starknet_getNonce', {\n contract_address,\n block_id,\n });\n }\n\n /**\n * Get the most recent accepted block hash and number\n */\n public getBlockLatestAccepted() {\n return this.fetchEndpoint('starknet_blockHashAndNumber');\n }\n\n /**\n * Get the most recent accepted block number\n * redundant use getBlockLatestAccepted();\n * @returns Number of the latest block\n */\n public getBlockNumber() {\n return this.fetchEndpoint('starknet_blockNumber');\n }\n\n public getBlockWithTxHashes(blockIdentifier: BlockIdentifier = this.blockIdentifier) {\n const block_id = new Block(blockIdentifier).identifier;\n return this.fetchEndpoint('starknet_getBlockWithTxHashes', { block_id });\n }\n\n public getBlockWithTxs(blockIdentifier: BlockIdentifier = this.blockIdentifier) {\n const block_id = new Block(blockIdentifier).identifier;\n return this.fetchEndpoint('starknet_getBlockWithTxs', { block_id });\n }\n\n public getBlockWithReceipts(blockIdentifier: BlockIdentifier = this.blockIdentifier) {\n const block_id = new Block(blockIdentifier).identifier;\n return this.fetchEndpoint('starknet_getBlockWithReceipts', { block_id });\n }\n\n public getBlockStateUpdate(blockIdentifier: BlockIdentifier = this.blockIdentifier) {\n const block_id = new Block(blockIdentifier).identifier;\n return this.fetchEndpoint('starknet_getStateUpdate', { block_id });\n }\n\n public getBlockTransactionsTraces(blockIdentifier: BlockIdentifier = this.blockIdentifier) {\n const block_id = new Block(blockIdentifier).identifier;\n return this.fetchEndpoint('starknet_traceBlockTransactions', { block_id });\n }\n\n public getBlockTransactionCount(blockIdentifier: BlockIdentifier = this.blockIdentifier) {\n const block_id = new Block(blockIdentifier).identifier;\n return this.fetchEndpoint('starknet_getBlockTransactionCount', { block_id });\n }\n\n public getTransactionByHash(txHash: BigNumberish) {\n const transaction_hash = toHex(txHash);\n return this.fetchEndpoint('starknet_getTransactionByHash', {\n transaction_hash,\n });\n }\n\n public getTransactionByBlockIdAndIndex(blockIdentifier: BlockIdentifier, index: number) {\n const block_id = new Block(blockIdentifier).identifier;\n return this.fetchEndpoint('starknet_getTransactionByBlockIdAndIndex', { block_id, index });\n }\n\n public getTransactionReceipt(txHash: BigNumberish) {\n const transaction_hash = toHex(txHash);\n return this.fetchEndpoint('starknet_getTransactionReceipt', { transaction_hash });\n }\n\n public getTransactionTrace(txHash: BigNumberish) {\n const transaction_hash = toHex(txHash);\n return this.fetchEndpoint('starknet_traceTransaction', { transaction_hash });\n }\n\n /**\n * Get the status of a transaction\n */\n public getTransactionStatus(transactionHash: BigNumberish) {\n const transaction_hash = toHex(transactionHash);\n return this.fetchEndpoint('starknet_getTransactionStatus', { transaction_hash });\n }\n\n /**\n * @param invocations AccountInvocations\n * @param simulateTransactionOptions blockIdentifier and flags to skip validation and fee charge<br/>\n * - blockIdentifier<br/>\n * - skipValidate (default false)<br/>\n * - skipFeeCharge (default true)<br/>\n */\n public simulateTransaction(\n invocations: AccountInvocations,\n simulateTransactionOptions: getSimulateTransactionOptions = {}\n ) {\n const {\n blockIdentifier = this.blockIdentifier,\n skipValidate = true,\n skipFeeCharge = true,\n } = simulateTransactionOptions;\n const block_id = new Block(blockIdentifier).identifier;\n const simulationFlags: RPC.ESimulationFlag[] = [];\n if (skipValidate) simulationFlags.push(RPC.ESimulationFlag.SKIP_VALIDATE);\n if (skipFeeCharge) simulationFlags.push(RPC.ESimulationFlag.SKIP_FEE_CHARGE);\n\n return this.fetchEndpoint('starknet_simulateTransactions', {\n block_id,\n transactions: invocations.map((it) => this.buildTransaction(it)),\n simulation_flags: simulationFlags,\n });\n }\n\n public async waitForTransaction(txHash: BigNumberish, options?: waitForTransactionOptions) {\n const transactionHash = toHex(txHash);\n let { retries } = this;\n let onchain = false;\n let isErrorState = false;\n const retryInterval = options?.retryInterval ?? this.transactionRetryIntervalDefault;\n const errorStates: any = options?.errorStates ?? [\n RPC.ETransactionStatus.REJECTED,\n // TODO: commented out to preserve the long-standing behavior of \"reverted\" not being treated as an error by default\n // should decide which behavior to keep in the future\n // RPC.ETransactionExecutionStatus.REVERTED,\n ];\n const successStates: any = options?.successStates ?? [\n RPC.ETransactionExecutionStatus.SUCCEEDED,\n RPC.ETransactionStatus.ACCEPTED_ON_L2,\n RPC.ETransactionStatus.ACCEPTED_ON_L1,\n ];\n\n let txStatus: RPC.TransactionStatus;\n while (!onchain) {\n // eslint-disable-next-line no-await-in-loop\n await wait(retryInterval);\n try {\n // eslint-disable-next-line no-await-in-loop\n txStatus = await this.getTransactionStatus(transactionHash);\n\n const executionStatus = txStatus.execution_status;\n const finalityStatus = txStatus.finality_status;\n\n if (!finalityStatus) {\n // Transaction is potentially NOT_RECEIVED or RPC not Synced yet\n // so we will retry '{ retries }' times\n const error = new Error('waiting for transaction status');\n throw error;\n }\n\n if (errorStates.includes(executionStatus) || errorStates.includes(finalityStatus)) {\n const message = `${executionStatus}: ${finalityStatus}`;\n const error = new Error(message) as Error & { response: RPC.TransactionStatus };\n error.response = txStatus;\n isErrorState = true;\n throw error;\n } else if (\n successStates.includes(executionStatus) ||\n successStates.includes(finalityStatus)\n ) {\n onchain = true;\n }\n } catch (error) {\n if (error instanceof Error && isErrorState) {\n throw error;\n }\n\n if (retries <= 0) {\n throw new Error(`waitForTransaction timed-out with retries ${this.retries}`);\n }\n }\n\n retries -= 1;\n }\n\n /**\n * For some nodes even though the transaction has executionStatus SUCCEEDED finalityStatus ACCEPTED_ON_L2, getTransactionReceipt returns \"Transaction hash not found\"\n * Retry until rpc is actually ready to work with txHash\n */\n let txReceipt = null;\n while (txReceipt === null) {\n try {\n // eslint-disable-next-line no-await-in-loop\n txReceipt = await this.getTransactionReceipt(transactionHash);\n } catch (error) {\n if (retries <= 0) {\n throw new Error(`waitForTransaction timed-out with retries ${this.retries}`);\n }\n }\n retries -= 1;\n // eslint-disable-next-line no-await-in-loop\n await wait(retryInterval);\n }\n return txReceipt as RPC.SPEC.TXN_RECEIPT;\n }\n\n public getStorageAt(\n contractAddress: BigNumberish,\n key: BigNumberish,\n blockIdentifier: BlockIdentifier = this.blockIdentifier\n ) {\n const contract_address = toHex(contractAddress);\n const parsedKey = toStorageKey(key);\n const block_id = new Block(blockIdentifier).identifier;\n return this.fetchEndpoint('starknet_getStorageAt', {\n contract_address,\n key: parsedKey,\n block_id,\n });\n }\n\n public getClassHashAt(\n contractAddress: BigNumberish,\n blockIdentifier: BlockIdentifier = this.blockIdentifier\n ) {\n const contract_address = toHex(contractAddress);\n const block_id = new Block(blockIdentifier).identifier;\n return this.fetchEndpoint('starknet_getClassHashAt', {\n block_id,\n contract_address,\n });\n }\n\n public getClass(\n classHash: BigNumberish,\n blockIdentifier: BlockIdentifier = this.blockIdentifier\n ) {\n const class_hash = toHex(classHash);\n const block_id = new Block(blockIdentifier).identifier;\n return this.fetchEndpoint('starknet_getClass', {\n class_hash,\n block_id,\n });\n }\n\n public getClassAt(\n contractAddress: BigNumberish,\n blockIdentifier: BlockIdentifier = this.blockIdentifier\n ) {\n const contract_address = toHex(contractAddress);\n const block_id = new Block(blockIdentifier).identifier;\n return this.fetchEndpoint('starknet_getClassAt', {\n block_id,\n contract_address,\n });\n }\n\n public async getEstimateFee(\n invocations: AccountInvocations,\n { blockIdentifier = this.blockIdentifier, skipValidate = true }: getEstimateFeeBulkOptions\n ) {\n const block_id = new Block(blockIdentifier).identifier;\n const flags = {\n simulation_flags: (skipValidate\n ? [RPC.ESimulationFlag.SKIP_VALIDATE]\n : []) as RPC.Methods['starknet_estimateFee']['params']['simulation_flags'],\n };\n\n return this.fetchEndpoint('starknet_estimateFee', {\n request: invocations.map((it) => this.buildTransaction(it, 'fee')),\n block_id,\n ...flags,\n });\n }\n\n public async invoke(functionInvocation: Invocation, details: InvocationsDetailsWithNonce) {\n let promise;\n if (!isV3Tx(details)) {\n // V1\n promise = this.fetchEndpoint('starknet_addInvokeTransaction', {\n invoke_transaction: {\n sender_address: functionInvocation.contractAddress,\n calldata: CallData.toHex(functionInvocation.calldata),\n type: RPC.ETransactionType.INVOKE,\n max_fee: toHex(details.maxFee || 0),\n version: RPC.ETransactionVersion.V1,\n signature: signatureToHexArray(functionInvocation.signature),\n nonce: toHex(details.nonce),\n },\n });\n\n logger.warn(SYSTEM_MESSAGES.legacyTxWarningMessage, {\n version: RPC.ETransactionVersion.V1,\n type: RPC.ETransactionType.INVOKE,\n });\n } else {\n // V3\n promise = this.fetchEndpoint('starknet_addInvokeTransaction', {\n invoke_transaction: {\n type: RPC.ETransactionType.INVOKE,\n sender_address: functionInvocation.contractAddress,\n calldata: CallData.toHex(functionInvocation.calldata),\n version: RPC.ETransactionVersion.V3,\n signature: signatureToHexArray(functionInvocation.signature),\n nonce: toHex(details.nonce),\n resource_bounds: details.resourceBounds,\n tip: toHex(details.tip),\n paymaster_data: details.paymasterData.map((it) => toHex(it)),\n account_deployment_data: details.accountDeploymentData.map((it) => toHex(it)),\n nonce_data_availability_mode: details.nonceDataAvailabilityMode,\n fee_data_availability_mode: details.feeDataAvailabilityMode,\n },\n });\n\n assertX(!(details as any).maxFee, () => {\n logger.warn(SYSTEM_MESSAGES.maxFeeInV3, {\n type: RPC.ETransactionType.INVOKE,\n });\n });\n }\n\n return this.waitMode ? this.waitForTransaction((await promise).transaction_hash) : promise;\n }\n\n public async declare(\n { contract, signature, senderAddress, compiledClassHash }: DeclareContractTransaction,\n details: InvocationsDetailsWithNonce\n ) {\n let promise;\n if (!isSierra(contract) && !isV3Tx(details)) {\n // V1 Cairo 0\n promise = this.fetchEndpoint('starknet_addDeclareTransaction', {\n declare_transaction: {\n type: RPC.ETransactionType.DECLARE,\n contract_class: {\n program: contract.program,\n entry_points_by_type: contract.entry_points_by_type,\n abi: contract.abi,\n },\n version: RPC.ETransactionVersion.V1,\n max_fee: toHex(details.maxFee || 0),\n signature: signatureToHexArray(signature),\n sender_address: senderAddress,\n nonce: toHex(details.nonce),\n },\n });\n\n logger.warn(SYSTEM_MESSAGES.legacyTxWarningMessage, {\n version: RPC.ETransactionVersion.V1,\n type: RPC.ETransactionType.DECLARE,\n });\n } else if (isSierra(contract) && !isV3Tx(details)) {\n // V2 Cairo1\n promise = this.fetchEndpoint('starknet_addDeclareTransaction', {\n declare_transaction: {\n type: RPC.ETransactionType.DECLARE,\n contract_class: {\n sierra_program: decompressProgram(contract.sierra_program),\n contract_class_version: contract.contract_class_version,\n entry_points_by_type: contract.entry_points_by_type,\n abi: contract.abi,\n },\n compiled_class_hash: compiledClassHash || '',\n version: RPC.ETransactionVersion.V2,\n max_fee: toHex(details.maxFee || 0),\n signature: signatureToHexArray(signature),\n sender_address: senderAddress,\n nonce: toHex(details.nonce),\n },\n });\n\n logger.warn(SYSTEM_MESSAGES.legacyTxWarningMessage, {\n version: RPC.ETransactionVersion.V2,\n type: RPC.ETransactionType.DECLARE,\n });\n } else if (isSierra(contract) && isV3Tx(details)) {\n // V3 Cairo1\n promise = this.fetchEndpoint('starknet_addDeclareTransaction', {\n declare_transaction: {\n type: RPC.ETransactionType.DECLARE,\n sender_address: senderAddress,\n compiled_class_hash: compiledClassHash || '',\n version: RPC.ETransactionVersion.V3,\n signature: signatureToHexArray(signature),\n nonce: toHex(details.nonce),\n contract_class: {\n sierra_program: decompressProgram(contract.sierra_program),\n contract_class_version: contract.contract_class_version,\n entry_points_by_type: contract.entry_points_by_type,\n abi: contract.abi,\n },\n resource_bounds: details.resourceBounds,\n tip: toHex(details.tip),\n paymaster_data: details.paymasterData.map((it) => toHex(it)),\n account_deployment_data: details.accountDeploymentData.map((it) => toHex(it)),\n nonce_data_availability_mode: details.nonceDataAvailabilityMode,\n fee_data_availability_mode: details.feeDataAvailabilityMode,\n },\n });\n\n assertX(!(details as any).maxFee, () => {\n logger.warn(SYSTEM_MESSAGES.maxFeeInV3, {\n type: RPC.ETransactionType.DECLARE,\n });\n });\n } else {\n throw Error('declare unspotted parameters');\n }\n\n return this.waitMode ? this.waitForTransaction((await promise).transaction_hash) : promise;\n }\n\n public async deployAccount(\n { classHash, constructorCalldata, addressSalt, signature }: DeployAccountContractTransaction,\n details: InvocationsDetailsWithNonce\n ) {\n let promise;\n if (!isV3Tx(details)) {\n // v1\n promise = this.fetchEndpoint('starknet_addDeployAccountTransaction', {\n deploy_account_transaction: {\n constructor_calldata: CallData.toHex(constructorCalldata || []),\n class_hash: toHex(classHash),\n contract_address_salt: toHex(addressSalt || 0),\n type: RPC.ETransactionType.DEPLOY_ACCOUNT,\n max_fee: toHex(details.maxFee || 0),\n version: RPC.ETransactionVersion.V1,\n signature: signatureToHexArray(signature),\n nonce: toHex(details.nonce),\n },\n });\n\n logger.warn(SYSTEM_MESSAGES.legacyTxWarningMessage, {\n version: RPC.ETransactionVersion.V1,\n type: RPC.ETransactionType.DEPLOY_ACCOUNT,\n });\n } else {\n // v3\n promise = this.fetchEndpoint('starknet_addDeployAccountTransaction', {\n deploy_account_transaction: {\n type: RPC.ETransactionType.DEPLOY_ACCOUNT,\n version: RPC.ETransactionVersion.V3,\n signature: signatureToHexArray(signature),\n nonce: toHex(details.nonce),\n contract_address_salt: toHex(addressSalt || 0),\n constructor_calldata: CallData.toHex(constructorCalldata || []),\n class_hash: toHex(classHash),\n resource_bounds: details.resourceBounds,\n tip: toHex(details.tip),\n paymaster_data: details.paymasterData.map((it) => toHex(it)),\n nonce_data_availability_mode: details.nonceDataAvailabilityMode,\n fee_data_availability_mode: details.feeDataAvailabilityMode,\n },\n });\n\n assertX(!(details as any).maxFee, () => {\n logger.warn(SYSTEM_MESSAGES.maxFeeInV3, {\n type: RPC.ETransactionType.DEPLOY_ACCOUNT,\n });\n });\n }\n\n return this.waitMode ? this.waitForTransaction((await promise).transaction_hash) : promise;\n }\n\n public callContract(call: Call, blockId