From 819434c6578801d9e8cdc7fb423d2d7e12745bc7 Mon Sep 17 00:00:00 2001 From: Maksim Zdobnikau <43750648+DelevoXDG@users.noreply.github.com> Date: Tue, 5 Mar 2024 19:22:07 +0100 Subject: [PATCH] Support RPC 0.7.0 (#409) --- .github/workflows/checks.yml | 2 +- lib/build.gradle.kts | 2 +- .../com/swmansion/starknet/account/Account.kt | 54 ++++ .../starknet/account/StandardAccount.kt | 37 +++ .../serializers/BlockPolymorphicSerializer.kt | 71 +++++ .../ExecutionResourcesSerializer.kt | 63 ---- .../GetBlockWithPolymorphicSerializer.kt | 34 --- ...TransactionReceiptPolymorphicSerializer.kt | 23 +- .../swmansion/starknet/data/types/Block.kt | 277 +++++++++++++++++- .../swmansion/starknet/data/types/Payloads.kt | 6 + .../starknet/data/types/Responses.kt | 218 ++++---------- .../types/transactions/ExecutionResources.kt | 38 --- .../data/types/transactions/Resources.kt | 98 +++++++ .../transactions/SimulatedTransaction.kt | 14 +- .../types/transactions/TransactionReceipt.kt | 192 +++--------- .../deployercontract/StandardDeployer.kt | 8 +- .../swmansion/starknet/provider/Provider.kt | 45 ++- .../starknet/provider/rpc/JsonRpcProvider.kt | 47 ++- .../kotlin/network/provider/ProviderTest.kt | 112 +++++-- .../starknet/account/StandardAccountTest.kt | 131 +++++++-- .../kotlin/starknet/crypto/FeeUtilsTest.kt | 59 +++- .../kotlin/starknet/provider/ProviderTest.kt | 227 ++++++++++++-- .../provider/response/JsonRpcResponseTest.kt | 2 + .../kotlin/starknet/utils/DevnetClient.kt | 4 +- 24 files changed, 1166 insertions(+), 598 deletions(-) create mode 100644 lib/src/main/kotlin/com/swmansion/starknet/data/serializers/BlockPolymorphicSerializer.kt delete mode 100644 lib/src/main/kotlin/com/swmansion/starknet/data/serializers/ExecutionResourcesSerializer.kt delete mode 100644 lib/src/main/kotlin/com/swmansion/starknet/data/serializers/GetBlockWithPolymorphicSerializer.kt delete mode 100644 lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/ExecutionResources.kt create mode 100644 lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/Resources.kt diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index fe08cff99..bd73adf4e 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -16,7 +16,7 @@ jobs: runs-on: ${{ matrix.os }} env: - DEVNET_SHA: 55191ee549b33ccbb0bc9d20dd929e39832a5ea5 + DEVNET_SHA: c6ffb99597eeea58d1a6a30fc061de69e586c779 steps: - uses: actions/checkout@v3 with: diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 53126afae..bff23ef26 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -8,7 +8,7 @@ import org.jetbrains.dokka.gradle.DokkaTask -version = "0.10.1" +version = "0.11.0" group = "com.swmansion.starknet" plugins { diff --git a/lib/src/main/kotlin/com/swmansion/starknet/account/Account.kt b/lib/src/main/kotlin/com/swmansion/starknet/account/Account.kt index 2fae401cb..c6dd7ccaa 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/account/Account.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/account/Account.kt @@ -320,6 +320,60 @@ interface Account { */ fun executeV3(call: Call, l1ResourceBounds: ResourceBounds): Request + /** + * Execute a list of calls using version 1 invoke transaction with automatically estimated fee + * that will be multiplied by the specified multiplier when max fee is calculated. + * + * @see [EstimateFeeResponse.toMaxFee] for algorithm used to calculate max fee. + * + * @param calls a list of calls to be executed. + * @param estimateFeeMultiplier how big multiplier should be used for the estimated fee. + * + * @return Invoke function response, containing transaction hash. + */ + fun executeV1(calls: List, estimateFeeMultiplier: Double): Request + + /** + * Execute a list of calls using version 3 invoke transaction with automatically estimated fee + * that will be multiplied by the specified multipliers when resource bounds are calculated. + * + * @see [EstimateFeeResponse.toResourceBounds] for algorithm used to calculate resource bounds. + * + * @param calls a list of calls to be executed. + * @param estimateAmountMultiplier how big multiplier should be used for the estimated amount. + * @param estimateUnitPriceMultiplier how big multiplier should be used for the estimated unit price. + * + * @return Invoke function response, containing transaction hash. + */ + fun executeV3(calls: List, estimateAmountMultiplier: Double, estimateUnitPriceMultiplier: Double): Request + + /** + * Execute single call using version 1 invoke transaction with automatically estimated fee + * that will be multiplied by the specified multiplier when max fee is calculated. + * + * @see [EstimateFeeResponse.toMaxFee] for algorithm used to calculate max fee. + * + * @param call a call to be executed. + * @param estimateFeeMultiplier how big multiplier should be used for the estimated fee. + * + * @return Invoke function response, containing transaction hash. + */ + fun executeV1(call: Call, estimateFeeMultiplier: Double): Request + + /** + * Execute single call using version 3 invoke transaction with automatically estimated fee + * that will be multiplied by the specified multipliers when resource bounds are calculated. + * + * @see [EstimateFeeResponse.toResourceBounds] for algorithm used to calculate resource bounds. + * + * @param call a call to be executed. + * @param estimateAmountMultiplier how big multiplier should be used for the estimated amount. + * @param estimateUnitPriceMultiplier how big multiplier should be used for the estimated unit price. + * + * @return Invoke function response, containing transaction hash. + */ + fun executeV3(call: Call, estimateAmountMultiplier: Double, estimateUnitPriceMultiplier: Double): Request + /** * Execute a list of calls with automatically estimated fee using version 1 invoke transaction. * diff --git a/lib/src/main/kotlin/com/swmansion/starknet/account/StandardAccount.kt b/lib/src/main/kotlin/com/swmansion/starknet/account/StandardAccount.kt index 0c414e4d3..dfd3d9593 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/account/StandardAccount.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/account/StandardAccount.kt @@ -260,6 +260,27 @@ class StandardAccount @JvmOverloads constructor( } } + override fun executeV1(calls: List, estimateFeeMultiplier: Double): Request { + return estimateFeeV1(calls).compose { estimateFee -> + val maxFee = estimateFee.first().toMaxFee(estimateFeeMultiplier) + executeV1(calls, maxFee) + } + } + + override fun executeV3( + calls: List, + estimateAmountMultiplier: Double, + estimateUnitPriceMultiplier: Double, + ): Request { + return estimateFeeV3(calls).compose { estimateFee -> + val resourceBounds = estimateFee.first().toResourceBounds( + amountMultiplier = estimateAmountMultiplier, + unitPriceMultiplier = estimateUnitPriceMultiplier, + ) + executeV3(calls, resourceBounds.l1Gas) + } + } + override fun executeV1(calls: List): Request { return estimateFeeV1(calls).compose { estimateFee -> val maxFee = estimateFee.first().toMaxFee() @@ -282,6 +303,22 @@ class StandardAccount @JvmOverloads constructor( return executeV3(listOf(call), l1ResourceBounds) } + override fun executeV1(call: Call, estimateFeeMultiplier: Double): Request { + return executeV1(listOf(call), estimateFeeMultiplier) + } + + override fun executeV3( + call: Call, + estimateAmountMultiplier: Double, + estimateUnitPriceMultiplier: Double, + ): Request { + return executeV3( + calls = listOf(call), + estimateAmountMultiplier = estimateAmountMultiplier, + estimateUnitPriceMultiplier = estimateUnitPriceMultiplier, + ) + } + override fun executeV1(call: Call): Request { return executeV1(listOf(call)) } diff --git a/lib/src/main/kotlin/com/swmansion/starknet/data/serializers/BlockPolymorphicSerializer.kt b/lib/src/main/kotlin/com/swmansion/starknet/data/serializers/BlockPolymorphicSerializer.kt new file mode 100644 index 000000000..2f14d9fd6 --- /dev/null +++ b/lib/src/main/kotlin/com/swmansion/starknet/data/serializers/BlockPolymorphicSerializer.kt @@ -0,0 +1,71 @@ +package com.swmansion.starknet.data.serializers + +import com.swmansion.starknet.data.types.* +import com.swmansion.starknet.data.types.transactions.* +import kotlinx.serialization.DeserializationStrategy +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.JsonContentPolymorphicSerializer +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.jsonObject + +internal object BlockWithTransactionsPolymorphicSerializer : JsonContentPolymorphicSerializer(BlockWithTransactions::class) { + override fun selectDeserializer(element: JsonElement): DeserializationStrategy { + return when (isPendingBlock(element.jsonObject)) { + true -> PendingBlockWithTransactions.serializer() + false -> ProcessedBlockWithTransactions.serializer() + } + } +} + +internal object BlockWithTransactionHashesPolymorphicSerializer : JsonContentPolymorphicSerializer(BlockWithTransactionHashes::class) { + override fun selectDeserializer(element: JsonElement): DeserializationStrategy { + return when (isPendingBlock(element.jsonObject)) { + true -> PendingBlockWithTransactionHashes.serializer() + false -> ProcessedBlockWithTransactionHashes.serializer() + } + } +} + +internal object BlockWithReceiptsPolymorphicSerializer : JsonContentPolymorphicSerializer(BlockWithReceipts::class) { + override fun selectDeserializer(element: JsonElement): DeserializationStrategy { + return when (isPendingBlock(element.jsonObject)) { + true -> PendingBlockWithReceipts.serializer() + false -> ProcessedBlockWithReceiptsSerializer + } + } +} + +internal object ProcessedBlockWithReceiptsSerializer : KSerializer { + override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ProcessedBlockWithReceipts", PrimitiveKind.STRING) + + override fun serialize(encoder: Encoder, value: ProcessedBlockWithReceipts) { + ProcessedBlockWithReceipts.serializer().serialize(encoder, value) + } + + override fun deserialize(decoder: Decoder): ProcessedBlockWithReceipts { + val block = ProcessedBlockWithReceipts.serializer().deserialize(decoder) + + val transactionsWithReceipts = block.transactionsWithReceipts.map { transactionWithReceipt -> + val updatedReceipt = when (val receipt = transactionWithReceipt.receipt) { + is InvokeTransactionReceipt -> receipt.copy(blockHash = block.blockHash, blockNumber = block.blockNumber) + is DeclareTransactionReceipt -> receipt.copy(blockHash = block.blockHash, blockNumber = block.blockNumber) + is DeployAccountTransactionReceipt -> receipt.copy(blockHash = block.blockHash, blockNumber = block.blockNumber) + is DeployTransactionReceipt -> receipt.copy(blockHash = block.blockHash, blockNumber = block.blockNumber) + is L1HandlerTransactionReceipt -> receipt.copy(blockHash = block.blockHash, blockNumber = block.blockNumber) + } + transactionWithReceipt.copy(receipt = updatedReceipt) + } + + return block.copy(transactionsWithReceipts = transactionsWithReceipts) + } +} + +private fun isPendingBlock(element: JsonObject): Boolean { + return listOf("block_hash", "block_number", "new_root").any { it !in element } +} diff --git a/lib/src/main/kotlin/com/swmansion/starknet/data/serializers/ExecutionResourcesSerializer.kt b/lib/src/main/kotlin/com/swmansion/starknet/data/serializers/ExecutionResourcesSerializer.kt deleted file mode 100644 index c07c9673c..000000000 --- a/lib/src/main/kotlin/com/swmansion/starknet/data/serializers/ExecutionResourcesSerializer.kt +++ /dev/null @@ -1,63 +0,0 @@ -package com.swmansion.starknet.data.serializers - -import com.swmansion.starknet.data.types.transactions.ExecutionResources -import com.swmansion.starknet.extensions.toNumAsHex -import kotlinx.serialization.KSerializer -import kotlinx.serialization.SerializationException -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import kotlinx.serialization.json.* - -// TODO: (#344) Remove this workaround serializer once ExecutionResources conform to the RPC spec on Pathfinder side. -internal object ExecutionResourcesSerializer : KSerializer { - override fun deserialize(decoder: Decoder): ExecutionResources { - // This accepts both integer and NUM_AS_HEX values, as a temporary workaround until this is fixed on Pathfinder side. - val input = decoder as? JsonDecoder ?: throw SerializationException("Expected JsonInput for ${decoder::class}") - - val jsonObject = input.decodeJsonElement().jsonObject - - // TODO (#344): This shoulde be a mandatory field, but it's not on Pathfinder side. - // val steps = getAsInt(jsonObject, "steps") ?: throw SerializationException("Input element does not contain mandatory field 'steps'") - val steps = getAsInt(jsonObject, "steps") ?: 0 - val memoryHoles = getAsInt(jsonObject, "memory_holes") - val rangeCheckApplications = getAsInt(jsonObject, "range_check_builtin_applications") - val pedersenApplications = getAsInt(jsonObject, "pedersen_builtin_applications") - val poseidonApplications = getAsInt(jsonObject, "poseidon_builtin_applications") - val ecOpApplications = getAsInt(jsonObject, "ec_op_builtin_applications") - val ecdsaApplications = getAsInt(jsonObject, "ecdsa_builtin_applications") - val bitwiseApplications = getAsInt(jsonObject, "bitwise_builtin_applications") - val keccakApplications = getAsInt(jsonObject, "keccak_builtin_applications") - val segmentArenaApplications = getAsInt(jsonObject, "segment_arena_builtin") - - return ExecutionResources( - steps = steps, - memoryHoles = memoryHoles, - rangeCheckApplications = rangeCheckApplications, - pedersenApplications = pedersenApplications, - poseidonApplications = poseidonApplications, - ecOpApplications = ecOpApplications, - ecdsaApplications = ecdsaApplications, - bitwiseApplications = bitwiseApplications, - keccakApplications = keccakApplications, - segmentArenaApplications = segmentArenaApplications, - ) - } - - override val descriptor: SerialDescriptor - get() = PrimitiveSerialDescriptor("ExecutionResources", PrimitiveKind.STRING) - - override fun serialize(encoder: Encoder, value: ExecutionResources) { - throw SerializationException("Class used for deserialization only.") - } - - private fun getAsInt(jsonObject: JsonObject, key: String): Int? { - return jsonObject.getOrDefault(key, null)?.jsonPrimitive?.contentOrNull?.let { fromHexOrInt(it) } - } - - private fun fromHexOrInt(value: String): Int { - return value.toBigIntegerOrNull()?.toInt() ?: value.toNumAsHex.value.toInt() - } -} diff --git a/lib/src/main/kotlin/com/swmansion/starknet/data/serializers/GetBlockWithPolymorphicSerializer.kt b/lib/src/main/kotlin/com/swmansion/starknet/data/serializers/GetBlockWithPolymorphicSerializer.kt deleted file mode 100644 index e7e63ca61..000000000 --- a/lib/src/main/kotlin/com/swmansion/starknet/data/serializers/GetBlockWithPolymorphicSerializer.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.swmansion.starknet.data.serializers - -import com.swmansion.starknet.data.types.BlockWithTransactionHashesResponse -import com.swmansion.starknet.data.types.BlockWithTransactionsResponse -import com.swmansion.starknet.data.types.GetBlockWithTransactionHashesResponse -import com.swmansion.starknet.data.types.GetBlockWithTransactionsResponse -import com.swmansion.starknet.data.types.PendingBlockWithTransactionHashesResponse -import com.swmansion.starknet.data.types.PendingBlockWithTransactionsResponse -import kotlinx.serialization.DeserializationStrategy -import kotlinx.serialization.json.JsonContentPolymorphicSerializer -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.jsonObject - -internal object GetBlockWithTransactionsPolymorphicSerializer : JsonContentPolymorphicSerializer(GetBlockWithTransactionsResponse::class) { - override fun selectDeserializer(element: JsonElement): DeserializationStrategy { - val isPendingBlock = listOf("block_hash", "block_number", "new_root").any { it !in element.jsonObject } - - return when (isPendingBlock) { - true -> PendingBlockWithTransactionsResponse.serializer() - false -> BlockWithTransactionsResponse.serializer() - } - } -} - -internal object GetBlockWithTransactionHashesPolymorphicSerializer : JsonContentPolymorphicSerializer(GetBlockWithTransactionHashesResponse::class) { - override fun selectDeserializer(element: JsonElement): DeserializationStrategy { - val isPendingBlock = listOf("block_hash", "block_number", "new_root").any { it !in element.jsonObject } - - return when (isPendingBlock) { - true -> PendingBlockWithTransactionHashesResponse.serializer() - false -> BlockWithTransactionHashesResponse.serializer() - } - } -} diff --git a/lib/src/main/kotlin/com/swmansion/starknet/data/serializers/TransactionReceiptPolymorphicSerializer.kt b/lib/src/main/kotlin/com/swmansion/starknet/data/serializers/TransactionReceiptPolymorphicSerializer.kt index d23fb7dcf..b8e1a41d6 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/data/serializers/TransactionReceiptPolymorphicSerializer.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/data/serializers/TransactionReceiptPolymorphicSerializer.kt @@ -12,26 +12,13 @@ internal object TransactionReceiptPolymorphicSerializer : val typeElement = jsonElement.getOrElse("type") { throw SerializationException("Input element does not contain mandatory field 'type'") } val type = Json.decodeFromJsonElement(TransactionType.serializer(), typeElement) - val isPending = listOf("block_hash", "block_number").any { it !in jsonElement } return when (type) { - TransactionType.INVOKE -> when (isPending) { - false -> ProcessedInvokeTransactionReceipt.serializer() - true -> PendingInvokeTransactionReceipt.serializer() - } - TransactionType.DECLARE -> when (isPending) { - false -> ProcessedDeclareTransactionReceipt.serializer() - true -> PendingDeclareTransactionReceipt.serializer() - } - TransactionType.DEPLOY_ACCOUNT -> when (isPending) { - false -> ProcessedDeployAccountTransactionReceipt.serializer() - true -> PendingDeployAccountTransactionReceipt.serializer() - } - TransactionType.DEPLOY -> ProcessedDeployTransactionReceipt.serializer() - TransactionType.L1_HANDLER -> when (isPending) { - false -> ProcessedL1HandlerTransactionReceipt.serializer() - true -> PendingL1HandlerTransactionReceipt.serializer() - } + TransactionType.INVOKE -> InvokeTransactionReceipt.serializer() + TransactionType.DEPLOY_ACCOUNT -> DeployAccountTransactionReceipt.serializer() + TransactionType.DECLARE -> DeclareTransactionReceipt.serializer() + TransactionType.L1_HANDLER -> L1HandlerTransactionReceipt.serializer() + TransactionType.DEPLOY -> DeployTransactionReceipt.serializer() } } } diff --git a/lib/src/main/kotlin/com/swmansion/starknet/data/types/Block.kt b/lib/src/main/kotlin/com/swmansion/starknet/data/types/Block.kt index cef202228..1fd148f43 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/data/types/Block.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/data/types/Block.kt @@ -1,32 +1,24 @@ package com.swmansion.starknet.data.types import com.swmansion.starknet.data.serializers.BlockIdSerializer -import kotlinx.serialization.ExperimentalSerializationApi +import com.swmansion.starknet.data.serializers.TransactionPolymorphicSerializer +import com.swmansion.starknet.data.serializers.TransactionReceiptPolymorphicSerializer +import com.swmansion.starknet.data.types.transactions.Transaction +import com.swmansion.starknet.data.types.transactions.TransactionReceipt +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonNames @Serializable enum class BlockTag(val tag: String) { LATEST("latest"), PENDING("pending") } -@OptIn(ExperimentalSerializationApi::class) @Serializable enum class BlockStatus { - @JsonNames("PENDING") PENDING, - - @JsonNames("ACCEPTED_ON_L1") ACCEPTED_ON_L1, - - @JsonNames("ACCEPTED_ON_L2") ACCEPTED_ON_L2, - - @JsonNames("REJECTED") REJECTED, - - @JsonNames("UNKNOWN") - UNKNOWN, } @Serializable(with = BlockIdSerializer::class) @@ -51,3 +43,262 @@ sealed class BlockId { } } } + +sealed interface Block { + val timestamp: Int + val sequencerAddress: Felt + val parentHash: Felt + val l1GasPrice: ResourcePrice + val l1DataGasPrice: ResourcePrice + val l1DataAvailabilityMode: L1DAMode + val starknetVersion: String +} + +/** + * Represents a processed block. + * + * Corresponds to the `BLOCK_HEADER` schema defined in the JSON-RPC spec. + */ +sealed interface ProcessedBlock : Block { + val status: BlockStatus + val blockHash: Felt + val blockNumber: Int + val newRoot: Felt +} + +/** + * Represents a pending block. + * + * Corresponds to the `PENDING_BLOCK_HEADER` schema defined in the JSON-RPC spec. + */ +sealed interface PendingBlock : Block + +@Serializable +sealed class BlockWithTransactions : Block { + abstract val transactions: List +} + +@Serializable +data class ProcessedBlockWithTransactions( + @SerialName("status") + override val status: BlockStatus, + + @SerialName("transactions") + override val transactions: List< + @Serializable(with = TransactionPolymorphicSerializer::class) + Transaction, + >, + + @SerialName("parent_hash") + override val parentHash: Felt, + + @SerialName("block_hash") + override val blockHash: Felt, + + @SerialName("block_number") + override val blockNumber: Int, + + @SerialName("new_root") + override val newRoot: Felt, + + @SerialName("timestamp") + override val timestamp: Int, + + @SerialName("sequencer_address") + override val sequencerAddress: Felt, + + @SerialName("l1_gas_price") + override val l1GasPrice: ResourcePrice, + + @SerialName("l1_data_gas_price") + override val l1DataGasPrice: ResourcePrice, + + @SerialName("l1_da_mode") + override val l1DataAvailabilityMode: L1DAMode, + + @SerialName("starknet_version") + override val starknetVersion: String, +) : BlockWithTransactions(), ProcessedBlock + +@Serializable +data class PendingBlockWithTransactions( + @SerialName("transactions") + override val transactions: List< + @Serializable(with = TransactionPolymorphicSerializer::class) + Transaction, + >, + + @SerialName("timestamp") + override val timestamp: Int, + + @SerialName("sequencer_address") + override val sequencerAddress: Felt, + + @SerialName("parent_hash") + override val parentHash: Felt, + + @SerialName("l1_gas_price") + override val l1GasPrice: ResourcePrice, + + @SerialName("l1_data_gas_price") + override val l1DataGasPrice: ResourcePrice, + + @SerialName("l1_da_mode") + override val l1DataAvailabilityMode: L1DAMode, + + @SerialName("starknet_version") + override val starknetVersion: String, +) : BlockWithTransactions(), PendingBlock + +@Serializable +data class TransactionWithReceipt( + @Serializable(with = TransactionPolymorphicSerializer::class) + @SerialName("transaction") + val transaction: Transaction, + + @Serializable(with = TransactionReceiptPolymorphicSerializer::class) + @SerialName("receipt") + val receipt: TransactionReceipt, +) + +@Serializable +sealed class BlockWithReceipts : Block { + abstract val transactionsWithReceipts: List +} + +@Serializable +data class ProcessedBlockWithReceipts( + @SerialName("status") + override val status: BlockStatus, + + @SerialName("transactions") + override val transactionsWithReceipts: List, + + @SerialName("block_hash") + override val blockHash: Felt, + + @SerialName("block_number") + override val blockNumber: Int, + + @SerialName("new_root") + override val newRoot: Felt, + + @SerialName("timestamp") + override val timestamp: Int, + + @SerialName("sequencer_address") + override val sequencerAddress: Felt, + + @SerialName("parent_hash") + override val parentHash: Felt, + + @SerialName("l1_gas_price") + override val l1GasPrice: ResourcePrice, + + @SerialName("l1_data_gas_price") + override val l1DataGasPrice: ResourcePrice, + + @SerialName("l1_da_mode") + override val l1DataAvailabilityMode: L1DAMode, + + @SerialName("starknet_version") + override val starknetVersion: String, +) : BlockWithReceipts(), ProcessedBlock + +@Serializable +data class PendingBlockWithReceipts( + @SerialName("transactions") + override val transactionsWithReceipts: List, + + @SerialName("timestamp") + override val timestamp: Int, + + @SerialName("sequencer_address") + override val sequencerAddress: Felt, + + @SerialName("parent_hash") + override val parentHash: Felt, + + @SerialName("l1_gas_price") + override val l1GasPrice: ResourcePrice, + + @SerialName("l1_data_gas_price") + override val l1DataGasPrice: ResourcePrice, + + @SerialName("l1_da_mode") + override val l1DataAvailabilityMode: L1DAMode, + + @SerialName("starknet_version") + override val starknetVersion: String, +) : BlockWithReceipts(), PendingBlock + +@Serializable +sealed class BlockWithTransactionHashes : Block { + abstract val transactionHashes: List +} + +@Serializable +data class ProcessedBlockWithTransactionHashes( + @SerialName("status") + override val status: BlockStatus, + + @SerialName("transactions") + override val transactionHashes: List, + + @SerialName("block_hash") + override val blockHash: Felt, + + @SerialName("block_number") + override val blockNumber: Int, + + @SerialName("new_root") + override val newRoot: Felt, + + @SerialName("timestamp") + override val timestamp: Int, + + @SerialName("sequencer_address") + override val sequencerAddress: Felt, + + @SerialName("parent_hash") + override val parentHash: Felt, + + @SerialName("l1_gas_price") + override val l1GasPrice: ResourcePrice, + + @SerialName("l1_data_gas_price") + override val l1DataGasPrice: ResourcePrice, + + @SerialName("l1_da_mode") + override val l1DataAvailabilityMode: L1DAMode, + + @SerialName("starknet_version") + override val starknetVersion: String, +) : BlockWithTransactionHashes(), ProcessedBlock + +@Serializable +data class PendingBlockWithTransactionHashes( + @SerialName("transactions") + override val transactionHashes: List, + + @SerialName("timestamp") + override val timestamp: Int, + + @SerialName("sequencer_address") + override val sequencerAddress: Felt, + + @SerialName("parent_hash") + override val parentHash: Felt, + + @SerialName("l1_gas_price") + override val l1GasPrice: ResourcePrice, + + @SerialName("l1_data_gas_price") + override val l1DataGasPrice: ResourcePrice, + + @SerialName("l1_da_mode") + override val l1DataAvailabilityMode: L1DAMode, + + @SerialName("starknet_version") + override val starknetVersion: String, +) : BlockWithTransactionHashes(), PendingBlock diff --git a/lib/src/main/kotlin/com/swmansion/starknet/data/types/Payloads.kt b/lib/src/main/kotlin/com/swmansion/starknet/data/types/Payloads.kt index 5413cbacd..f9bc79271 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/data/types/Payloads.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/data/types/Payloads.kt @@ -96,6 +96,12 @@ internal data class GetBlockWithTransactionHashesPayload( override val blockId: BlockId, ) : PayloadWithBlockId() +@Serializable +internal data class GetBlockWithReceiptsPayload( + @SerialName("block_id") + override val blockId: BlockId, +) : PayloadWithBlockId() + @Serializable internal data class GetStateUpdatePayload( @SerialName("block_id") diff --git a/lib/src/main/kotlin/com/swmansion/starknet/data/types/Responses.kt b/lib/src/main/kotlin/com/swmansion/starknet/data/types/Responses.kt index 91b254f8c..42983c73c 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/data/types/Responses.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/data/types/Responses.kt @@ -1,8 +1,6 @@ package com.swmansion.starknet.data.types import com.swmansion.starknet.data.serializers.HexToIntDeserializer -import com.swmansion.starknet.data.serializers.TransactionPolymorphicSerializer -import com.swmansion.starknet.data.types.transactions.Transaction import com.swmansion.starknet.data.types.transactions.TransactionExecutionStatus import com.swmansion.starknet.data.types.transactions.TransactionStatus import com.swmansion.starknet.extensions.* @@ -52,6 +50,12 @@ data class EstimateFeeResponse( @SerialName("gas_price") val gasPrice: Felt, + @SerialName("data_gas_consumed") + val dataGasConsumed: Felt, + + @SerialName("data_gas_price") + val dataGasPrice: Felt, + @SerialName("overall_fee") val overallFee: Felt, @@ -59,24 +63,50 @@ data class EstimateFeeResponse( @SerialName("unit") val feeUnit: PriceUnit? = null, ) { - fun toMaxFee(overhead: Double = 0.5): Felt { - return addOverhead(overallFee.value, overhead).toFelt + /** + * Convert estimated fee to max fee with applied multiplier. + * + * Multiplies [overallFee] by round([multiplier] * 100%) and performs integer division by 100. + * + * @param multiplier Multiplier for max fee, defaults to 1.5. + */ + fun toMaxFee(multiplier: Double = 1.5): Felt { + require(multiplier >= 0) + + return overallFee.value.applyMultiplier(multiplier).toFelt } + /** + * Convert estimated fee to resource bounds with applied multipliers. + * + * Calculates max amount as maxAmount = [overallFee] / [gasPrice], unless [gasPrice] is 0, then maxAmount is 0. + * Calculates max price per unit as maxPricePerUnit = [gasPrice]. + * Then multiplies maxAmount by round([amountMultiplier] * 100%) and maxPricePerUnit by round([unitPriceMultiplier] * 100%) and performs integer division by 100 on both. + * + * @param amountMultiplier Multiplier for max amount, defaults to 1.5. + * @param unitPriceMultiplier Multiplier for max price per unit, defaults to 1.5. + * + * @return Resource bounds with applied multipliers. + */ fun toResourceBounds( - amountOverhead: Double = 0.1, - unitPriceOverhead: Double = 0.5, + amountMultiplier: Double = 1.5, + unitPriceMultiplier: Double = 1.5, ): ResourceBoundsMapping { - val maxAmount = addOverhead(gasConsumed.value, amountOverhead).toUint64 - val maxPricePerUnit = addOverhead(gasPrice.value, unitPriceOverhead).toUint128 + require(amountMultiplier >= 0) + require(unitPriceMultiplier >= 0) + + val maxAmount = when (gasPrice) { + Felt.ZERO -> Uint64.ZERO + else -> (overallFee.value / gasPrice.value).applyMultiplier(amountMultiplier).toUint64 + } + val maxPricePerUnit = gasPrice.value.applyMultiplier(unitPriceMultiplier).toUint128 return ResourceBoundsMapping( l1Gas = ResourceBounds(maxAmount = maxAmount, maxPricePerUnit = maxPricePerUnit), ) } - private fun addOverhead(value: BigInteger, overhead: Double): BigInteger { - val multiplier = ((1 + overhead) * 100).roundToInt().toBigInteger() - return value.multiply(multiplier).divide(BigInteger.valueOf(100)) + private fun BigInteger.applyMultiplier(multiplier: Double): BigInteger { + return (this * (multiplier * 100).roundToInt().toBigInteger()) / BigInteger.valueOf(100) } } @@ -160,163 +190,6 @@ data class SyncingResponse( override val highestBlockNumber: Int, ) : Syncing() -@Serializable -sealed class GetBlockWithTransactionsResponse { - abstract val transactions: List - abstract val timestamp: Int - abstract val sequencerAddress: Felt - abstract val parentHash: Felt - abstract val l1GasPrice: ResourcePrice - abstract val starknetVersion: String -} - -@Serializable -data class BlockWithTransactionsResponse( - @SerialName("status") - val status: BlockStatus, - - // Block body - - @SerialName("transactions") - override val transactions: List< - @Serializable(with = TransactionPolymorphicSerializer::class) - Transaction, - >, - - // Block header - - @SerialName("parent_hash") - override val parentHash: Felt, - - @SerialName("block_hash") - val blockHash: Felt, - - @SerialName("block_number") - val blockNumber: Int, - - @SerialName("new_root") - val newRoot: Felt, - - @SerialName("timestamp") - override val timestamp: Int, - - @SerialName("sequencer_address") - override val sequencerAddress: Felt, - - @SerialName("l1_gas_price") - override val l1GasPrice: ResourcePrice, - - @SerialName("starknet_version") - override val starknetVersion: String, -) : GetBlockWithTransactionsResponse() - -@Serializable -data class PendingBlockWithTransactionsResponse( - // Not in RPC schema, but can be returned by nodes - @SerialName("status") - val status: BlockStatus = BlockStatus.PENDING, - - // Block body - - @SerialName("transactions") - override val transactions: List< - @Serializable(with = TransactionPolymorphicSerializer::class) - Transaction, - >, - - // Pending block header - - @SerialName("timestamp") - override val timestamp: Int, - - @SerialName("sequencer_address") - override val sequencerAddress: Felt, - - @SerialName("parent_hash") - override val parentHash: Felt, - - @SerialName("l1_gas_price") - override val l1GasPrice: ResourcePrice, - - @SerialName("starknet_version") - override val starknetVersion: String, -) : GetBlockWithTransactionsResponse() - -sealed class GetBlockWithTransactionHashesResponse { - abstract val timestamp: Int - abstract val sequencerAddress: Felt - abstract val parentHash: Felt - abstract val transactionHashes: List - abstract val l1GasPrice: ResourcePrice - abstract val starknetVersion: String -} - -@Serializable -data class BlockWithTransactionHashesResponse( - @SerialName("status") - val status: BlockStatus, - - // Block body - - @SerialName("transactions") - override val transactionHashes: List, - - // Block header - - @SerialName("block_hash") - val blockHash: Felt, - - @SerialName("block_number") - val blockNumber: Int, - - @SerialName("new_root") - val newRoot: Felt, - - @SerialName("timestamp") - override val timestamp: Int, - - @SerialName("sequencer_address") - override val sequencerAddress: Felt, - - @SerialName("parent_hash") - override val parentHash: Felt, - - @SerialName("l1_gas_price") - override val l1GasPrice: ResourcePrice, - - @SerialName("starknet_version") - override val starknetVersion: String, -) : GetBlockWithTransactionHashesResponse() - -@Serializable -data class PendingBlockWithTransactionHashesResponse( - // Not in RPC schema, but can be returned by nodes - @SerialName("status") - val status: BlockStatus = BlockStatus.PENDING, - - // Block body - - @SerialName("transactions") - override val transactionHashes: List, - - // Pending block header - - @SerialName("timestamp") - override val timestamp: Int, - - @SerialName("sequencer_address") - override val sequencerAddress: Felt, - - @SerialName("parent_hash") - override val parentHash: Felt, - - @SerialName("l1_gas_price") - override val l1GasPrice: ResourcePrice, - - @SerialName("starknet_version") - override val starknetVersion: String, -) : GetBlockWithTransactionHashesResponse() - @Serializable data class StorageEntries( @SerialName("key") @@ -494,3 +367,12 @@ enum class PriceUnit { @JsonNames("STRK") // TODO: (#344) RPC 0.5.0 legacy name, remove once Pathfinder is updated FRI, } + +@Serializable +enum class L1DAMode { + @SerialName("BLOB") + BLOB, + + @SerialName("CALLDATA") + CALLDATA, +} diff --git a/lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/ExecutionResources.kt b/lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/ExecutionResources.kt deleted file mode 100644 index e99e2f278..000000000 --- a/lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/ExecutionResources.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.swmansion.starknet.data.types.transactions - -import com.swmansion.starknet.data.serializers.ExecutionResourcesSerializer -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable - -@Serializable(with = ExecutionResourcesSerializer::class) -data class ExecutionResources( - @SerialName("steps") - val steps: Int, - - @SerialName("memory_holes") - val memoryHoles: Int? = null, - - @SerialName("range_check_builtin_applications") - val rangeCheckApplications: Int? = null, - - @SerialName("pedersen_builtin_applications") - val pedersenApplications: Int? = null, - - @SerialName("poseidon_builtin_applications") - val poseidonApplications: Int? = null, - - @SerialName("ec_op_builtin_applications") - val ecOpApplications: Int? = null, - - @SerialName("ecdsa_builtin_applications") - val ecdsaApplications: Int? = null, - - @SerialName("bitwise_builtin_applications") - val bitwiseApplications: Int? = null, - - @SerialName("keccak_builtin_applications") - val keccakApplications: Int? = null, - - @SerialName("segment_arena_builtin") - val segmentArenaApplications: Int? = null, -) diff --git a/lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/Resources.kt b/lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/Resources.kt new file mode 100644 index 000000000..d77cf225f --- /dev/null +++ b/lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/Resources.kt @@ -0,0 +1,98 @@ +@file:JvmName("Resources") + +package com.swmansion.starknet.data.types.transactions + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +sealed class Resources { + abstract val steps: Int + abstract val memoryHoles: Int? + abstract val rangeCheckApplications: Int? + abstract val pedersenApplications: Int? + abstract val poseidonApplications: Int? + abstract val ecOpApplications: Int? + abstract val ecdsaApplications: Int? + abstract val bitwiseApplications: Int? + abstract val keccakApplications: Int? + abstract val segmentArenaApplications: Int? +} + +@Serializable +data class ComputationResources( + @SerialName("steps") + override val steps: Int, + + @SerialName("memory_holes") + override val memoryHoles: Int? = null, + + @SerialName("range_check_builtin_applications") + override val rangeCheckApplications: Int? = null, + + @SerialName("pedersen_builtin_applications") + override val pedersenApplications: Int? = null, + + @SerialName("poseidon_builtin_applications") + override val poseidonApplications: Int? = null, + + @SerialName("ec_op_builtin_applications") + override val ecOpApplications: Int? = null, + + @SerialName("ecdsa_builtin_applications") + override val ecdsaApplications: Int? = null, + + @SerialName("bitwise_builtin_applications") + override val bitwiseApplications: Int? = null, + + @SerialName("keccak_builtin_applications") + override val keccakApplications: Int? = null, + + @SerialName("segment_arena_builtin") + override val segmentArenaApplications: Int? = null, +) : Resources() + +@Serializable +data class ExecutionResources( + @SerialName("steps") + override val steps: Int, + + @SerialName("memory_holes") + override val memoryHoles: Int? = null, + + @SerialName("range_check_builtin_applications") + override val rangeCheckApplications: Int? = null, + + @SerialName("pedersen_builtin_applications") + override val pedersenApplications: Int? = null, + + @SerialName("poseidon_builtin_applications") + override val poseidonApplications: Int? = null, + + @SerialName("ec_op_builtin_applications") + override val ecOpApplications: Int? = null, + + @SerialName("ecdsa_builtin_applications") + override val ecdsaApplications: Int? = null, + + @SerialName("bitwise_builtin_applications") + override val bitwiseApplications: Int? = null, + + @SerialName("keccak_builtin_applications") + override val keccakApplications: Int? = null, + + @SerialName("segment_arena_builtin") + override val segmentArenaApplications: Int? = null, + + @SerialName("data_availability") + val dataAvailability: DataResources, +) : Resources() + +@Serializable +data class DataResources( + @SerialName("l1_gas") + val l1Gas: Int, + + @SerialName("l1_data_gas") + val l1DataGas: Int, +) diff --git a/lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/SimulatedTransaction.kt b/lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/SimulatedTransaction.kt index a1e6aa7f1..d29479370 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/SimulatedTransaction.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/SimulatedTransaction.kt @@ -71,7 +71,7 @@ data class FunctionInvocation( val messages: List, @SerialName("execution_resources") - val executionResources: ExecutionResources, + val computationResources: ComputationResources, ) @Serializable @@ -111,6 +111,9 @@ data class InvokeTransactionTrace( @SerialName("state_diff") override val stateDiff: StateDiff? = null, + + @SerialName("execution_resources") + val executionResources: ExecutionResources, ) : InvokeTransactionTraceBase() @Serializable @@ -126,6 +129,9 @@ data class RevertedInvokeTransactionTrace( @SerialName("state_diff") override val stateDiff: StateDiff? = null, + + @SerialName("execution_resources") + val executionResources: ExecutionResources, ) : InvokeTransactionTraceBase() @Serializable @@ -139,6 +145,9 @@ data class DeclareTransactionTrace( @SerialName("state_diff") override val stateDiff: StateDiff? = null, + @SerialName("execution_resources") + val executionResources: ExecutionResources, + @SerialName("type") override val type: TransactionType = TransactionType.DECLARE, ) : TransactionTrace() @@ -157,6 +166,9 @@ data class DeployAccountTransactionTrace( @SerialName("state_diff") override val stateDiff: StateDiff? = null, + @SerialName("execution_resources") + val executionResources: ExecutionResources, + @SerialName("type") override val type: TransactionType, ) : TransactionTrace() diff --git a/lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/TransactionReceipt.kt b/lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/TransactionReceipt.kt index f974a17d0..675597ba0 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/TransactionReceipt.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/TransactionReceipt.kt @@ -70,29 +70,31 @@ sealed class TransactionReceipt { abstract val events: List abstract val messagesSent: List abstract val executionResources: ExecutionResources + abstract val blockHash: Felt? + abstract val blockNumber: Int? val isAccepted: Boolean get() = ( executionStatus == TransactionExecutionStatus.SUCCEEDED && (finalityStatus == TransactionFinalityStatus.ACCEPTED_ON_L1 || finalityStatus == TransactionFinalityStatus.ACCEPTED_ON_L2) ) - abstract val isPending: Boolean -} - -@Serializable -sealed class ProcessedTransactionReceipt : TransactionReceipt() { - abstract val blockHash: Felt - abstract val blockNumber: Int - override val isPending: Boolean = false -} -@Serializable -sealed class PendingTransactionReceipt : TransactionReceipt() { - override val isPending: Boolean = true + val isPending: Boolean + get() = !hasBlockInfo && finalityStatus == TransactionFinalityStatus.ACCEPTED_ON_L2 + + /** + * Checks if the receipt contains block information. + * + * This method verifies whether the receipt conforms to the `TXN_RECEIPT_WITH_BLOCK_INFO` schema as defined in the JSON-RPC spec. + * + * @return `true` if both [blockHash] and [blockNumber] are not `null`; `false` otherwise. + */ + val hasBlockInfo: Boolean + get() = listOf(blockHash, blockNumber).all { it != null } } @Serializable -data class ProcessedInvokeTransactionReceipt( +data class InvokeTransactionReceipt( @SerialName("transaction_hash") override val hash: Felt, @@ -106,10 +108,10 @@ data class ProcessedInvokeTransactionReceipt( override val finalityStatus: TransactionFinalityStatus, @SerialName("block_hash") - override val blockHash: Felt, + override val blockHash: Felt? = null, @SerialName("block_number") - override val blockNumber: Int, + override val blockNumber: Int? = null, @SerialName("type") override val type: TransactionType = TransactionType.INVOKE, @@ -125,40 +127,10 @@ data class ProcessedInvokeTransactionReceipt( @SerialName("execution_resources") override val executionResources: ExecutionResources, -) : ProcessedTransactionReceipt() +) : TransactionReceipt() @Serializable -data class PendingInvokeTransactionReceipt( - @SerialName("transaction_hash") - override val hash: Felt, - - @SerialName("actual_fee") - override val actualFee: FeePayment, - - @SerialName("messages_sent") - override val messagesSent: List, - - @SerialName("events") - override val events: List, - - @SerialName("type") - override val type: TransactionType = TransactionType.INVOKE, - - @SerialName("revert_reason") - override val revertReason: String? = null, - - @SerialName("finality_status") - override val finalityStatus: TransactionFinalityStatus = TransactionFinalityStatus.ACCEPTED_ON_L2, - - @SerialName("execution_status") - override val executionStatus: TransactionExecutionStatus, - - @SerialName("execution_resources") - override val executionResources: ExecutionResources, -) : PendingTransactionReceipt() - -@Serializable -data class ProcessedDeclareTransactionReceipt( +data class DeclareTransactionReceipt( @SerialName("transaction_hash") override val hash: Felt, @@ -172,10 +144,10 @@ data class ProcessedDeclareTransactionReceipt( override val finalityStatus: TransactionFinalityStatus, @SerialName("block_hash") - override val blockHash: Felt, + override val blockHash: Felt? = null, @SerialName("block_number") - override val blockNumber: Int, + override val blockNumber: Int? = null, override val type: TransactionType = TransactionType.DECLARE, @@ -190,40 +162,10 @@ data class ProcessedDeclareTransactionReceipt( @SerialName("execution_resources") override val executionResources: ExecutionResources, -) : ProcessedTransactionReceipt() - -@Serializable -data class PendingDeclareTransactionReceipt( - @SerialName("transaction_hash") - override val hash: Felt, - - @SerialName("actual_fee") - override val actualFee: FeePayment, - - @SerialName("messages_sent") - override val messagesSent: List, - - @SerialName("events") - override val events: List, - - @SerialName("type") - override val type: TransactionType = TransactionType.DECLARE, - - @SerialName("revert_reason") - override val revertReason: String? = null, - - @SerialName("finality_status") - override val finalityStatus: TransactionFinalityStatus = TransactionFinalityStatus.ACCEPTED_ON_L2, - - @SerialName("execution_status") - override val executionStatus: TransactionExecutionStatus, - - @SerialName("execution_resources") - override val executionResources: ExecutionResources, -) : PendingTransactionReceipt() +) : TransactionReceipt() @Serializable -data class ProcessedDeployAccountTransactionReceipt( +data class DeployAccountTransactionReceipt( @SerialName("transaction_hash") override val hash: Felt, @@ -237,10 +179,10 @@ data class ProcessedDeployAccountTransactionReceipt( override val finalityStatus: TransactionFinalityStatus, @SerialName("block_hash") - override val blockHash: Felt, + override val blockHash: Felt? = null, @SerialName("block_number") - override val blockNumber: Int, + override val blockNumber: Int? = null, @SerialName("type") override val type: TransactionType = TransactionType.DEPLOY_ACCOUNT, @@ -259,43 +201,10 @@ data class ProcessedDeployAccountTransactionReceipt( @SerialName("contract_address") val contractAddress: Felt, -) : ProcessedTransactionReceipt() +) : TransactionReceipt() @Serializable -data class PendingDeployAccountTransactionReceipt( - @SerialName("transaction_hash") - override val hash: Felt, - - @SerialName("actual_fee") - override val actualFee: FeePayment, - - @SerialName("messages_sent") - override val messagesSent: List, - - @SerialName("events") - override val events: List, - - @SerialName("type") - override val type: TransactionType = TransactionType.DEPLOY_ACCOUNT, - - @SerialName("revert_reason") - override val revertReason: String? = null, - - @SerialName("finality_status") - override val finalityStatus: TransactionFinalityStatus = TransactionFinalityStatus.ACCEPTED_ON_L2, - - @SerialName("execution_status") - override val executionStatus: TransactionExecutionStatus, - - @SerialName("execution_resources") - override val executionResources: ExecutionResources, - - @SerialName("contract_address") - val contractAddress: Felt, -) : PendingTransactionReceipt() - -@Serializable -data class ProcessedDeployTransactionReceipt( +data class DeployTransactionReceipt( @SerialName("transaction_hash") override val hash: Felt, @@ -309,10 +218,10 @@ data class ProcessedDeployTransactionReceipt( override val finalityStatus: TransactionFinalityStatus, @SerialName("block_hash") - override val blockHash: Felt, + override val blockHash: Felt? = null, @SerialName("block_number") - override val blockNumber: Int, + override val blockNumber: Int? = null, @SerialName("type") override val type: TransactionType, @@ -331,10 +240,10 @@ data class ProcessedDeployTransactionReceipt( @SerialName("contract_address") val contractAddress: Felt, -) : ProcessedTransactionReceipt() +) : TransactionReceipt() @Serializable -data class ProcessedL1HandlerTransactionReceipt( +data class L1HandlerTransactionReceipt( @SerialName("transaction_hash") override val hash: Felt, @@ -348,10 +257,10 @@ data class ProcessedL1HandlerTransactionReceipt( override val finalityStatus: TransactionFinalityStatus, @SerialName("block_hash") - override val blockHash: Felt, + override val blockHash: Felt? = null, @SerialName("block_number") - override val blockNumber: Int, + override val blockNumber: Int? = null, @SerialName("type") override val type: TransactionType = TransactionType.L1_HANDLER, @@ -370,37 +279,4 @@ data class ProcessedL1HandlerTransactionReceipt( @SerialName("message_hash") val messageHash: NumAsHex, -) : ProcessedTransactionReceipt() - -@Serializable -data class PendingL1HandlerTransactionReceipt( - @SerialName("transaction_hash") - override val hash: Felt, - - @SerialName("actual_fee") - override val actualFee: FeePayment, - - @SerialName("messages_sent") - override val messagesSent: List, - - @SerialName("events") - override val events: List, - - @SerialName("type") - override val type: TransactionType = TransactionType.L1_HANDLER, - - @SerialName("revert_reason") - override val revertReason: String? = null, - - @SerialName("finality_status") - override val finalityStatus: TransactionFinalityStatus = TransactionFinalityStatus.ACCEPTED_ON_L2, - - @SerialName("execution_status") - override val executionStatus: TransactionExecutionStatus, - - @SerialName("execution_resources") - override val executionResources: ExecutionResources, - - @SerialName("message_hash") - val messageHash: Felt, -) : PendingTransactionReceipt() +) : TransactionReceipt() diff --git a/lib/src/main/kotlin/com/swmansion/starknet/deployercontract/StandardDeployer.kt b/lib/src/main/kotlin/com/swmansion/starknet/deployercontract/StandardDeployer.kt index e6b28ebfb..ab50826fd 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/deployercontract/StandardDeployer.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/deployercontract/StandardDeployer.kt @@ -105,11 +105,9 @@ class StandardDeployer( contractDeployment: ContractDeployment, ): Event? { val events = when (transactionReceipt) { - is PendingInvokeTransactionReceipt -> transactionReceipt.events - is ProcessedInvokeTransactionReceipt -> transactionReceipt.events - is ProcessedDeployTransactionReceipt -> transactionReceipt.events - is PendingDeployAccountTransactionReceipt -> transactionReceipt.events - is ProcessedDeployAccountTransactionReceipt -> transactionReceipt.events + is InvokeTransactionReceipt -> transactionReceipt.events + is DeployTransactionReceipt -> transactionReceipt.events + is DeployAccountTransactionReceipt -> transactionReceipt.events else -> throw AddressRetrievalFailedException("Invalid transaction type", contractDeployment) } val deploymentEvents = events.filter { it.keys.contains(selectorFromName("ContractDeployed")) } diff --git a/lib/src/main/kotlin/com/swmansion/starknet/provider/Provider.kt b/lib/src/main/kotlin/com/swmansion/starknet/provider/Provider.kt index c4bb044dd..1f24758d1 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/provider/Provider.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/provider/Provider.kt @@ -639,7 +639,7 @@ interface Provider { * * @throws RequestFailedException */ - fun getBlockWithTxs(blockTag: BlockTag): Request + fun getBlockWithTxs(blockTag: BlockTag): Request /** * Get a block with transactions. @@ -650,7 +650,7 @@ interface Provider { * * @throws RequestFailedException */ - fun getBlockWithTxs(blockHash: Felt): Request + fun getBlockWithTxs(blockHash: Felt): Request /** * Get a block with transactions. @@ -661,7 +661,7 @@ interface Provider { * * @throws RequestFailedException */ - fun getBlockWithTxs(blockNumber: Int): Request + fun getBlockWithTxs(blockNumber: Int): Request /** * Get a block with transaction hashes. @@ -672,7 +672,7 @@ interface Provider { * * @throws RequestFailedException */ - fun getBlockWithTxHashes(blockTag: BlockTag): Request + fun getBlockWithTxHashes(blockTag: BlockTag): Request /** * Get a block with transaction hashes. @@ -683,7 +683,7 @@ interface Provider { * * @throws RequestFailedException */ - fun getBlockWithTxHashes(blockHash: Felt): Request + fun getBlockWithTxHashes(blockHash: Felt): Request /** * Get a block with transaction hashes. @@ -694,7 +694,40 @@ interface Provider { * * @throws RequestFailedException */ - fun getBlockWithTxHashes(blockNumber: Int): Request + fun getBlockWithTxHashes(blockNumber: Int): Request + + /** + * Get a block with transaction receipts. + * + * Get block information with transaction receipts given the block id. + * + * @param blockTag a tag of the requested block + * + * @throws RequestFailedException + */ + fun getBlockWithReceipts(blockTag: BlockTag): Request + + /** + * Get a block with transaction receipts. + * + * Get block information with transaction receipts given the block id. + * + * @param blockHash a hash of the requested block + * + * @throws RequestFailedException + */ + fun getBlockWithReceipts(blockHash: Felt): Request + + /** + * Get a block with transaction receipts. + * + * Get block information with transaction receipts given the block id. + * + * @param blockNumber a number of the requested block + * + * @throws RequestFailedException + */ + fun getBlockWithReceipts(blockNumber: Int): Request /** * Get block state information. diff --git a/lib/src/main/kotlin/com/swmansion/starknet/provider/rpc/JsonRpcProvider.kt b/lib/src/main/kotlin/com/swmansion/starknet/provider/rpc/JsonRpcProvider.kt index 9c7985a76..cd15717dc 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/provider/rpc/JsonRpcProvider.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/provider/rpc/JsonRpcProvider.kt @@ -1,7 +1,7 @@ package com.swmansion.starknet.provider.rpc import com.swmansion.starknet.data.serializers.* -import com.swmansion.starknet.data.serializers.GetBlockWithTransactionsPolymorphicSerializer +import com.swmansion.starknet.data.serializers.BlockWithTransactionsPolymorphicSerializer import com.swmansion.starknet.data.serializers.SyncPolymorphicSerializer import com.swmansion.starknet.data.serializers.TransactionPolymorphicSerializer import com.swmansion.starknet.data.serializers.TransactionReceiptPolymorphicSerializer @@ -494,52 +494,76 @@ class JsonRpcProvider( return buildRequest(JsonRpcMethod.GET_CHAIN_ID, params, StarknetChainId.serializer()) } - private fun getBlockWithTxs(payload: GetBlockWithTransactionsPayload): Request { + private fun getBlockWithTxs(payload: GetBlockWithTransactionsPayload): Request { val jsonPayload = Json.encodeToJsonElement(payload) - return buildRequest(JsonRpcMethod.GET_BLOCK_WITH_TXS, jsonPayload, GetBlockWithTransactionsPolymorphicSerializer) + return buildRequest(JsonRpcMethod.GET_BLOCK_WITH_TXS, jsonPayload, BlockWithTransactionsPolymorphicSerializer) } - override fun getBlockWithTxs(blockTag: BlockTag): Request { + override fun getBlockWithTxs(blockTag: BlockTag): Request { val payload = GetBlockWithTransactionsPayload(BlockId.Tag(blockTag)) return getBlockWithTxs(payload) } - override fun getBlockWithTxs(blockHash: Felt): Request { + override fun getBlockWithTxs(blockHash: Felt): Request { val payload = GetBlockWithTransactionsPayload(BlockId.Hash(blockHash)) return getBlockWithTxs(payload) } - override fun getBlockWithTxs(blockNumber: Int): Request { + override fun getBlockWithTxs(blockNumber: Int): Request { val payload = GetBlockWithTransactionsPayload(BlockId.Number(blockNumber)) return getBlockWithTxs(payload) } - override fun getBlockWithTxHashes(blockTag: BlockTag): Request { + override fun getBlockWithTxHashes(blockTag: BlockTag): Request { val payload = GetBlockWithTransactionHashesPayload(BlockId.Tag(blockTag)) return getBlockWithTxHashes(payload) } - override fun getBlockWithTxHashes(blockHash: Felt): Request { + override fun getBlockWithTxHashes(blockHash: Felt): Request { val payload = GetBlockWithTransactionHashesPayload(BlockId.Hash(blockHash)) return getBlockWithTxHashes(payload) } - override fun getBlockWithTxHashes(blockNumber: Int): Request { + override fun getBlockWithTxHashes(blockNumber: Int): Request { val payload = GetBlockWithTransactionHashesPayload(BlockId.Number(blockNumber)) return getBlockWithTxHashes(payload) } - private fun getBlockWithTxHashes(payload: GetBlockWithTransactionHashesPayload): Request { + private fun getBlockWithTxHashes(payload: GetBlockWithTransactionHashesPayload): Request { val jsonPayload = Json.encodeToJsonElement(payload) - return buildRequest(JsonRpcMethod.GET_BLOCK_WITH_TX_HASHES, jsonPayload, GetBlockWithTransactionHashesPolymorphicSerializer) + return buildRequest(JsonRpcMethod.GET_BLOCK_WITH_TX_HASHES, jsonPayload, BlockWithTransactionHashesPolymorphicSerializer) + } + + override fun getBlockWithReceipts(blockTag: BlockTag): Request { + val payload = GetBlockWithReceiptsPayload(BlockId.Tag(blockTag)) + + return getBlockWithReceipts(payload) + } + + override fun getBlockWithReceipts(blockHash: Felt): Request { + val payload = GetBlockWithReceiptsPayload(BlockId.Hash(blockHash)) + + return getBlockWithReceipts(payload) + } + + override fun getBlockWithReceipts(blockNumber: Int): Request { + val payload = GetBlockWithReceiptsPayload(BlockId.Number(blockNumber)) + + return getBlockWithReceipts(payload) + } + + private fun getBlockWithReceipts(payload: GetBlockWithReceiptsPayload): Request { + val jsonPayload = Json.encodeToJsonElement(payload) + + return buildRequest(JsonRpcMethod.GET_BLOCK_WITH_RECEIPTS, jsonPayload, BlockWithReceiptsPolymorphicSerializer) } private fun getStateUpdate(payload: GetStateUpdatePayload): Request { @@ -637,6 +661,7 @@ private enum class JsonRpcMethod(val methodName: String) { ESTIMATE_MESSAGE_FEE("starknet_estimateMessageFee"), GET_BLOCK_WITH_TXS("starknet_getBlockWithTxs"), GET_BLOCK_WITH_TX_HASHES("starknet_getBlockWithTxHashes"), + GET_BLOCK_WITH_RECEIPTS("starknet_getBlockWithReceipts"), GET_STATE_UPDATE("starknet_getStateUpdate"), GET_TRANSACTION_BY_BLOCK_ID_AND_INDEX("starknet_getTransactionByBlockIdAndIndex"), GET_NONCE("starknet_getNonce"), diff --git a/lib/src/test/kotlin/network/provider/ProviderTest.kt b/lib/src/test/kotlin/network/provider/ProviderTest.kt index a317ed8d5..7dee0d44d 100644 --- a/lib/src/test/kotlin/network/provider/ProviderTest.kt +++ b/lib/src/test/kotlin/network/provider/ProviderTest.kt @@ -145,7 +145,8 @@ class ProviderTest { val receiptRequest = provider.getTransactionReceipt(transactionHash) val receipt = receiptRequest.send() - assertTrue(receipt is ProcessedDeployAccountTransactionReceipt) + assertTrue(receipt is DeployAccountTransactionReceipt) + assertFalse(receipt.isPending) assertTrue(receipt.isAccepted) assertNull(receipt.revertReason) } @@ -166,7 +167,8 @@ class ProviderTest { val receiptRequest = provider.getTransactionReceipt(transactionHash) val receipt = receiptRequest.send() - assertTrue(receipt is ProcessedDeployAccountTransactionReceipt) + assertTrue(receipt is DeployAccountTransactionReceipt) + assertFalse(receipt.isPending) assertTrue(receipt.isAccepted) assertNull(receipt.revertReason) } @@ -182,7 +184,8 @@ class ProviderTest { val receiptRequest = provider.getTransactionReceipt(transactionHash) val receipt = receiptRequest.send() - assertTrue(receipt is ProcessedInvokeTransactionReceipt) + assertTrue(receipt is InvokeTransactionReceipt) + assertFalse(receipt.isPending) assertFalse(receipt.isAccepted) assertEquals(TransactionExecutionStatus.REVERTED, receipt.executionStatus) assertNotNull(receipt.revertReason) @@ -207,7 +210,8 @@ class ProviderTest { assertTrue(receipt.isAccepted) assertNull(receipt.revertReason) - assertTrue(receipt is ProcessedInvokeTransactionReceipt) + assertTrue(receipt is InvokeTransactionReceipt) + assertFalse(receipt.isPending) } @Test @@ -234,7 +238,8 @@ class ProviderTest { assertTrue(receipt.isAccepted) assertNull(receipt.revertReason) - assertTrue(receipt is ProcessedInvokeTransactionReceipt) + assertTrue(receipt is InvokeTransactionReceipt) + assertFalse(receipt.isPending) } @Test @@ -257,7 +262,8 @@ class ProviderTest { } assertNull(receipt.revertReason) - receipt is ProcessedDeclareTransactionReceipt + receipt is DeclareTransactionReceipt + assertFalse(receipt.isPending) assertEquals(Felt.ZERO, receipt.actualFee.amount) assertEquals(PriceUnit.WEI, receipt.actualFee.unit) } @@ -274,7 +280,8 @@ class ProviderTest { val receiptRequest = provider.getTransactionReceipt(transactionHash) val receipt = receiptRequest.send() - assertTrue(receipt is ProcessedDeclareTransactionReceipt) + assertTrue(receipt is DeclareTransactionReceipt) + assertFalse(receipt.isPending) assertTrue(receipt.isAccepted) assertEquals(TransactionExecutionStatus.SUCCEEDED, receipt.executionStatus) assertEquals(TransactionFinalityStatus.ACCEPTED_ON_L1, receipt.finalityStatus) @@ -293,7 +300,8 @@ class ProviderTest { val receiptRequest = provider.getTransactionReceipt(transactionHash) val receipt = receiptRequest.send() - assertTrue(receipt is ProcessedDeclareTransactionReceipt) + assertTrue(receipt is DeclareTransactionReceipt) + assertFalse(receipt.isPending) assertTrue(receipt.isAccepted) assertNull(receipt.revertReason) } @@ -314,7 +322,8 @@ class ProviderTest { val receiptRequest = provider.getTransactionReceipt(transactionHash) val receipt = receiptRequest.send() - assertTrue(receipt is ProcessedDeclareTransactionReceipt) + assertTrue(receipt is DeclareTransactionReceipt) + assertFalse(receipt.isPending) assertTrue(receipt.isAccepted) assertNull(receipt.revertReason) } @@ -336,7 +345,8 @@ class ProviderTest { val receiptRequest = provider.getTransactionReceipt(transactionHash) val receipt = receiptRequest.send() - assertTrue(receipt is ProcessedL1HandlerTransactionReceipt) + assertTrue(receipt is L1HandlerTransactionReceipt) + assertFalse(receipt.isPending) assertTrue(receipt.isAccepted) assertNull(receipt.revertReason) @@ -347,7 +357,7 @@ class ProviderTest { Network.SEPOLIA_TESTNET -> NumAsHex.fromHex("0x42e76df4e3d5255262929c27132bd0d295a8d3db2cfe63d2fcd061c7a7a7ab34") } - assertEquals(expectedMessageHash, (receipt as ProcessedL1HandlerTransactionReceipt).messageHash) + assertEquals(expectedMessageHash, (receipt as L1HandlerTransactionReceipt).messageHash) } @Test @@ -364,7 +374,7 @@ class ProviderTest { val receiptRequest = provider.getTransactionReceipt(transactionHash) val receipt = receiptRequest.send() - assertTrue(receipt is ProcessedTransactionReceipt) + assertFalse(receipt.isPending) assertTrue(receipt.isAccepted) assertEquals(2, receipt.messagesSent.size) @@ -381,7 +391,7 @@ class ProviderTest { val response = request.send() assertNotNull(response) - assertTrue(response is BlockWithTransactionsResponse) + assertTrue(response is ProcessedBlockWithTransactions) } @Disabled @@ -397,7 +407,7 @@ class ProviderTest { val response = request.send() assertNotNull(response) - assertTrue(response is PendingBlockWithTransactionsResponse) + assertTrue(response is PendingBlockWithTransactions) } @Test @@ -409,7 +419,7 @@ class ProviderTest { val response = request.send() assertNotNull(response) - assertTrue(response is BlockWithTransactionsResponse) + assertTrue(response is ProcessedBlockWithTransactions) assertTrue(response.transactions.size >= 4) } @@ -422,7 +432,7 @@ class ProviderTest { val response = request.send() assertNotNull(response) - assertTrue(response is BlockWithTransactionsResponse) + assertTrue(response is ProcessedBlockWithTransactions) assertTrue(response.transactions.size >= 4) } @@ -434,7 +444,7 @@ class ProviderTest { val response = request.send() assertNotNull(response) - assertTrue(response is BlockWithTransactionHashesResponse) + assertTrue(response is ProcessedBlockWithTransactionHashes) } @Disabled @@ -450,7 +460,7 @@ class ProviderTest { val response = request.send() assertNotNull(response) - assertTrue(response is PendingBlockWithTransactionHashesResponse) + assertTrue(response is PendingBlockWithTransactionHashes) } @Test @@ -462,7 +472,7 @@ class ProviderTest { val response = request.send() assertNotNull(response) - assertTrue(response is BlockWithTransactionHashesResponse) + assertTrue(response is ProcessedBlockWithTransactionHashes) assertTrue(response.transactionHashes.size >= 4) } @@ -475,7 +485,69 @@ class ProviderTest { val response = request.send() assertNotNull(response) - assertTrue(response is BlockWithTransactionHashesResponse) + assertTrue(response is ProcessedBlockWithTransactionHashes) assertTrue(response.transactionHashes.size >= 4) } + + @Test + fun `get block with receipts with latest block tag`() { + assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) + + val request = provider.getBlockWithReceipts(BlockTag.LATEST) + val response = request.send() + + assertNotNull(response) + assertTrue(response is ProcessedBlockWithReceipts) + } + + @Disabled + @Test + fun `get block with receipts with pending block tag`() { + assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) + // Note to future developers experiencing failures in this test: + // 1. This test may fail because there's temporarily no pending block at the moment. + // If this happens, try running the test again after a while or disable it. + // 2. The node can be configured such way that accessing pending block is not supported. + + val request = provider.getBlockWithReceipts(BlockTag.PENDING) + val response = request.send() + + assertNotNull(response) + assertTrue(response is PendingBlockWithReceipts) + response.transactionsWithReceipts.forEach { + assertTrue(it.receipt.isPending) + } + } + + @Test + fun `get block with receipts with block hash`() { + assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) + + val blockHash = specificBlockHash + val request = provider.getBlockWithReceipts(blockHash) + val response = request.send() + + assertNotNull(response) + assertTrue(response is ProcessedBlockWithReceipts) + assertTrue(response.transactionsWithReceipts.size >= 4) + response.transactionsWithReceipts.forEach { + assertFalse(it.receipt.isPending) + } + } + + @Test + fun `get block with receipts with block number`() { + assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) + + val blockNumber = specificBlockNumber + val request = provider.getBlockWithReceipts(blockNumber) + val response = request.send() + + assertNotNull(response) + assertTrue(response is ProcessedBlockWithReceipts) + assertTrue(response.transactionsWithReceipts.size >= 4) + response.transactionsWithReceipts.forEach { + assertFalse(it.receipt.isPending) + } + } } diff --git a/lib/src/test/kotlin/starknet/account/StandardAccountTest.kt b/lib/src/test/kotlin/starknet/account/StandardAccountTest.kt index 0509153d5..192470fdc 100644 --- a/lib/src/test/kotlin/starknet/account/StandardAccountTest.kt +++ b/lib/src/test/kotlin/starknet/account/StandardAccountTest.kt @@ -145,7 +145,10 @@ class StandardAccountTest { val feeEstimate = request.send().first() assertNotEquals(Felt.ZERO, feeEstimate.overallFee) - assertEquals(feeEstimate.gasPrice.value.multiply(feeEstimate.gasConsumed.value), feeEstimate.overallFee.value) + assertEquals( + feeEstimate.gasPrice.value * feeEstimate.gasConsumed.value + feeEstimate.dataGasPrice.value * feeEstimate.dataGasConsumed.value, + feeEstimate.overallFee.value, + ) } @Test @@ -159,7 +162,10 @@ class StandardAccountTest { val feeEstimate = request.send().first() assertNotEquals(Felt.ZERO, feeEstimate.overallFee) - assertEquals(feeEstimate.gasPrice.value.multiply(feeEstimate.gasConsumed.value), feeEstimate.overallFee.value) + assertEquals( + feeEstimate.gasPrice.value * feeEstimate.gasConsumed.value + feeEstimate.dataGasPrice.value * feeEstimate.dataGasConsumed.value, + feeEstimate.overallFee.value, + ) } @Test @@ -191,7 +197,10 @@ class StandardAccountTest { val feeEstimates = request.send() feeEstimates.forEach { assertNotEquals(Felt.ZERO, it.overallFee) - assertEquals(it.gasPrice.value.multiply(it.gasConsumed.value), it.overallFee.value) + assertEquals( + it.gasPrice.value * it.gasConsumed.value + it.dataGasPrice.value * it.dataGasConsumed.value, + it.overallFee.value, + ) } } @@ -203,7 +212,10 @@ class StandardAccountTest { val feeEstimate = request.send().first() assertNotEquals(Felt.ZERO, feeEstimate.overallFee) - assertEquals(feeEstimate.gasPrice.value.multiply(feeEstimate.gasConsumed.value), feeEstimate.overallFee.value) + assertEquals( + feeEstimate.gasPrice.value * feeEstimate.gasConsumed.value + feeEstimate.dataGasPrice.value * feeEstimate.dataGasConsumed.value, + feeEstimate.overallFee.value, + ) } } @@ -232,7 +244,10 @@ class StandardAccountTest { val feeEstimate = request.send().first() assertNotEquals(Felt.ZERO, feeEstimate.overallFee) - assertEquals(feeEstimate.gasPrice.value.multiply(feeEstimate.gasConsumed.value), feeEstimate.overallFee.value) + assertEquals( + feeEstimate.gasPrice.value * feeEstimate.gasConsumed.value + feeEstimate.dataGasPrice.value * feeEstimate.dataGasConsumed.value, + feeEstimate.overallFee.value, + ) } @Test @@ -257,7 +272,11 @@ class StandardAccountTest { val feeEstimate = request.send().first() assertNotEquals(Felt.ZERO, feeEstimate.overallFee) - assertEquals(feeEstimate.gasPrice.value.multiply(feeEstimate.gasConsumed.value), feeEstimate.overallFee.value) } + assertEquals( + feeEstimate.gasPrice.value * feeEstimate.gasConsumed.value + feeEstimate.dataGasPrice.value * feeEstimate.dataGasConsumed.value, + feeEstimate.overallFee.value, + ) + } @Test fun `estimate fee for declare v3 transaction`() { @@ -282,7 +301,10 @@ class StandardAccountTest { val feeEstimate = request.send().first() assertNotEquals(Felt.ZERO, feeEstimate.overallFee) - assertEquals(feeEstimate.gasPrice.value.multiply(feeEstimate.gasConsumed.value), feeEstimate.overallFee.value) + assertEquals( + feeEstimate.gasPrice.value * feeEstimate.gasConsumed.value + feeEstimate.dataGasPrice.value * feeEstimate.dataGasConsumed.value, + feeEstimate.overallFee.value, + ) } } @@ -322,9 +344,10 @@ class StandardAccountTest { val response = request.send() assertNotEquals(Felt.ZERO, response.gasPrice) - assertNotEquals(Felt.ZERO, response.gasConsumed) - assertNotEquals(Felt.ZERO, response.overallFee) - assertEquals(response.gasPrice.value.multiply(response.gasConsumed.value), response.overallFee.value) + assertEquals( + response.gasPrice.value * response.gasConsumed.value + response.dataGasPrice.value * response.dataGasConsumed.value, + response.overallFee.value, + ) } @Nested @@ -358,6 +381,8 @@ class StandardAccountTest { @Test fun `sign and send declare v2 transaction`() { + devnetClient.prefundAccountEth(accountAddress) + val contractCode = Path.of("src/test/resources/contracts_v1/target/release/ContractsV1_HelloStarknet.sierra.json").readText() val casmCode = Path.of("src/test/resources/contracts_v1/target/release/ContractsV1_HelloStarknet.casm.json").readText() @@ -368,7 +393,7 @@ class StandardAccountTest { val declareTransactionPayload = account.signDeclareV2( contractDefinition, contractCasmDefinition, - ExecutionParams(nonce, Felt(1000000000000000L)), + ExecutionParams(nonce, Felt(5000000000000000L)), ) val request = provider.declareContract(declareTransactionPayload) val result = request.send() @@ -380,6 +405,8 @@ class StandardAccountTest { @Test fun `sign and send declare v2 transaction (cairo compiler v2)`() { + devnetClient.prefundAccountEth(accountAddress) + val contractCode = Path.of("src/test/resources/contracts_v2/target/release/ContractsV2_CounterContract.sierra.json").readText() val casmCode = Path.of("src/test/resources/contracts_v2/target/release/ContractsV2_CounterContract.casm.json").readText() @@ -390,7 +417,7 @@ class StandardAccountTest { val declareTransactionPayload = account.signDeclareV2( contractDefinition, contractCasmDefinition, - ExecutionParams(nonce, Felt(1000000000000000)), + ExecutionParams(nonce, Felt(10000000000000000)), ) val request = provider.declareContract(declareTransactionPayload) val result = request.send() @@ -402,6 +429,8 @@ class StandardAccountTest { @Test fun `sign and send declare v3 transaction`() { + devnetClient.prefundAccountStrk(accountAddress) + ScarbClient.buildSaltedContract( placeholderContractPath = Path.of("src/test/resources/contracts_v2/src/placeholder_counter_contract.cairo"), saltedContractPath = Path.of("src/test/resources/contracts_v2/src/salted_counter_contract.cairo"), @@ -416,8 +445,8 @@ class StandardAccountTest { val params = DeclareParamsV3( nonce = nonce, l1ResourceBounds = ResourceBounds( - maxAmount = Uint64(20000), - maxPricePerUnit = Uint128(120000000000), + maxAmount = Uint64(100000), + maxPricePerUnit = Uint128(1000000000000), ), ) val declareTransactionPayload = account.signDeclareV3( @@ -482,7 +511,7 @@ class StandardAccountTest { @Nested inner class InvokeTest { @Test - fun `sign single call`() { + fun `sign v1 single call`() { val call = Call( contractAddress = balanceContractAddress, calldata = listOf(Felt(10)), @@ -529,7 +558,7 @@ class StandardAccountTest { } @Test - fun `execute single call`() { + fun `execute v1 single call`() { val call = Call( contractAddress = balanceContractAddress, entrypoint = "increase_balance", @@ -559,7 +588,41 @@ class StandardAccountTest { } @Test - fun `execute single call with specific fee`() { + fun `execute v1 single call with specific fee estimate multiplier`() { + val call = Call( + contractAddress = balanceContractAddress, + entrypoint = "increase_balance", + calldata = listOf(Felt(10)), + ) + + val result = account.executeV1(call, estimateFeeMultiplier = 1.59).send() + + val receipt = provider.getTransactionReceipt(result.transactionHash).send() + + assertTrue(receipt.isAccepted) + } + + @Test + fun `execute v3 single call with specific fee estimate multiplier`() { + val call = Call( + contractAddress = balanceContractAddress, + entrypoint = "increase_balance", + calldata = listOf(Felt(10)), + ) + + val result = account.executeV3( + call, + estimateAmountMultiplier = 1.59, + estimateUnitPriceMultiplier = 1.39, + ).send() + + val receipt = provider.getTransactionReceipt(result.transactionHash).send() + + assertTrue(receipt.isAccepted) + } + + @Test + fun `execute v1 single call with specific fee`() { // Note to future developers experiencing failures in this test: // This transaction may fail if the fee is too low. val call = Call( @@ -600,7 +663,7 @@ class StandardAccountTest { } @Test - fun `sign multiple calls test`() { + fun `sign v1 multiple calls test`() { val call = Call( contractAddress = balanceContractAddress, entrypoint = "increase_balance", @@ -645,7 +708,7 @@ class StandardAccountTest { } @Test - fun `execute multiple calls`() { + fun `execute v1 multiple calls`() { val call1 = Call( contractAddress = balanceContractAddress, entrypoint = "increase_balance", @@ -687,7 +750,7 @@ class StandardAccountTest { } @Test - fun `two executes with single call`() { + fun `two executes v1 with single call`() { val call = Call( contractAddress = balanceContractAddress, entrypoint = "increase_balance", @@ -1169,6 +1232,8 @@ class StandardAccountTest { @Test fun `simulate declare v2 transaction`() { + devnetClient.prefundAccountEth(accountAddress) + ScarbClient.buildSaltedContract( placeholderContractPath = Path.of("src/test/resources/contracts_v1/src/placeholder_hello_starknet.cairo"), saltedContractPath = Path.of("src/test/resources/contracts_v1/src/salted_hello_starknet.cairo"), @@ -1189,7 +1254,7 @@ class StandardAccountTest { casmContractDefinition, ExecutionParams( nonce = nonce, - maxFee = Felt(1000000000000000L), + maxFee = Felt(3000000000000000), ), ) @@ -1206,6 +1271,8 @@ class StandardAccountTest { @Test fun `simulate declare v3 transaction`() { + devnetClient.prefundAccountStrk(accountAddress) + ScarbClient.buildSaltedContract( placeholderContractPath = Path.of("src/test/resources/contracts_v1/src/placeholder_hello_starknet.cairo"), saltedContractPath = Path.of("src/test/resources/contracts_v1/src/salted_hello_starknet.cairo"), @@ -1227,8 +1294,8 @@ class StandardAccountTest { DeclareParamsV3( nonce = nonce, l1ResourceBounds = ResourceBounds( - maxAmount = Uint64(20000), - maxPricePerUnit = Uint128(120000000000), + maxAmount = Uint64(100000), + maxPricePerUnit = Uint128(1000000000000), ), ), ) @@ -1257,12 +1324,21 @@ class StandardAccountTest { "fee_estimation": { "gas_consumed": "0x9d8", "gas_price": "0x3b9aca2f", + "data_gas_consumed": "0x3a", + "data_gas_price": "0x1a05", "overall_fee": "0x24abbb63ea8" }, "transaction_trace": { "type": "INVOKE", "execute_invocation": { "revert_reason": "Placeholder revert reason." + }, + "execution_resources": { + "steps": 582, + "data_availability": { + "l1_gas": "123", + "l1_data_gas": "456" + } } } } @@ -1306,6 +1382,8 @@ class StandardAccountTest { "fee_estimation": { "gas_consumed": "0x9d8", "gas_price": "0x3b9aca2f", + "data_gas_consumed": "0x3a", + "data_gas_price": "0x1a05", "overall_fee": "0x24abbb63ea8" }, "transaction_trace": { @@ -1378,6 +1456,13 @@ class StandardAccountTest { "execution_resources": { "steps": 800 } + }, + "execution_resources": { + "steps": 1600, + "data_availability": { + "l1_gas": "123", + "l1_data_gas": "456" + } } } } diff --git a/lib/src/test/kotlin/starknet/crypto/FeeUtilsTest.kt b/lib/src/test/kotlin/starknet/crypto/FeeUtilsTest.kt index e802d8d8b..83dc66ebe 100644 --- a/lib/src/test/kotlin/starknet/crypto/FeeUtilsTest.kt +++ b/lib/src/test/kotlin/starknet/crypto/FeeUtilsTest.kt @@ -4,13 +4,16 @@ import com.swmansion.starknet.data.types.* import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows class FeeUtilsTest { companion object { val estimateFee = EstimateFeeResponse( gasConsumed = Felt(1000), gasPrice = Felt(100), - overallFee = Felt(1000 * 100), + dataGasConsumed = Felt(200), + dataGasPrice = Felt(50), + overallFee = Felt(1000 * 100 + 200 * 50), // 110000 feeUnit = PriceUnit.WEI, ) } @@ -21,21 +24,28 @@ class FeeUtilsTest { fun `estimate fee to max fee - default`() { val result = estimateFee.toMaxFee() - assertEquals(result, Felt(150000)) + assertEquals(result, Felt(165000)) } @Test - fun `estimate fee to max fee - specific overhead`() { - val result = estimateFee.toMaxFee(0.13) + fun `estimate fee to max fee - specific multiplier`() { + val result = estimateFee.toMaxFee(1.13) - assertEquals(result, Felt(113000)) + assertEquals(result, Felt(124300)) } @Test - fun `estimate fee to max fee - 0 overhead`() { - val result = estimateFee.toMaxFee(0.0) + fun `estimate fee to max fee - 1 multiplier`() { + val result = estimateFee.toMaxFee(1.0) - assertEquals(result, Felt(100000)) + assertEquals(result, Felt(110000)) + } + + @Test + fun `estimate fee to max fee - negative multiplier`() { + assertThrows { + estimateFee.toMaxFee(-1.0) + } } } @@ -45,27 +55,46 @@ class FeeUtilsTest { fun `estimate fee to resource bounds - default`() { val result = estimateFee.toResourceBounds() val expected = ResourceBoundsMapping( - l1Gas = ResourceBounds(maxAmount = Uint64(1100), maxPricePerUnit = Uint128(150)), + l1Gas = ResourceBounds( + maxAmount = Uint64(1650), + maxPricePerUnit = Uint128(150), + ), ) assertEquals(expected, result) } @Test - fun `estimate fee to resource bounds - specific overhead`() { - val result = estimateFee.toResourceBounds(0.19, 0.13) + fun `estimate fee to resource bounds - specific multiplier`() { + val result = estimateFee.toResourceBounds(1.19, 1.13) val expected = ResourceBoundsMapping( - l1Gas = ResourceBounds(maxAmount = Uint64(1190), maxPricePerUnit = Uint128(113)), + l1Gas = ResourceBounds( + maxAmount = Uint64(1309), + maxPricePerUnit = Uint128(113), + ), ) assertEquals(expected, result) } @Test - fun `estimate fee to resource bounds - 0 overhead`() { - val result = estimateFee.toResourceBounds(0.0, 0.0) + fun `estimate fee to resource bounds - 1 multiplier`() { + val result = estimateFee.toResourceBounds(1.0, 1.0) val expected = ResourceBoundsMapping( - l1Gas = ResourceBounds(maxAmount = Uint64(1000), maxPricePerUnit = Uint128(100)), + l1Gas = ResourceBounds( + maxAmount = Uint64(1100), + maxPricePerUnit = Uint128(100), + ), ) assertEquals(expected, result) } + + @Test + fun `estimate fee to resource bounds - negative multiplier`() { + assertThrows { + estimateFee.toResourceBounds(-1.0, 1.0) + } + assertThrows { + estimateFee.toResourceBounds(1.0, -1.0) + } + } } } diff --git a/lib/src/test/kotlin/starknet/provider/ProviderTest.kt b/lib/src/test/kotlin/starknet/provider/ProviderTest.kt index 95ac34c10..2425c56e7 100644 --- a/lib/src/test/kotlin/starknet/provider/ProviderTest.kt +++ b/lib/src/test/kotlin/starknet/provider/ProviderTest.kt @@ -333,7 +333,11 @@ class ProviderTest { "ec_op_builtin_applications": "123", "ecdsa_builtin_applications": "789", "bitwise_builtin_applications": "1", - "keccak_builtin_applications": "1" + "keccak_builtin_applications": "1", + "data_availability": { + "l1_gas": "123", + "l1_data_gas": "456" + } } } } @@ -345,7 +349,9 @@ class ProviderTest { val request = provider.getTransactionReceipt(Felt.ZERO) val response = request.send() - assertTrue(response is ProcessedDeployTransactionReceipt) + assertTrue(response is DeployTransactionReceipt) + assertFalse(response.isPending) + assertTrue(response.hasBlockInfo) } @Test @@ -353,7 +359,9 @@ class ProviderTest { val request = provider.getTransactionReceipt(declareTransactionHash) val response = request.send() - assertTrue(response is ProcessedDeclareTransactionReceipt) + assertTrue(response is DeclareTransactionReceipt) + assertFalse(response.isPending) + assertTrue(response.hasBlockInfo) } @Test @@ -361,7 +369,9 @@ class ProviderTest { val request = provider.getTransactionReceipt(invokeTransactionHash) val response = request.send() - assertTrue(response is ProcessedInvokeTransactionReceipt) + assertTrue(response is InvokeTransactionReceipt) + assertFalse(response.isPending) + assertTrue(response.hasBlockInfo) } @Test @@ -392,7 +402,11 @@ class ProviderTest { "ec_op_builtin_applications": "123", "ecdsa_builtin_applications": "789", "bitwise_builtin_applications": "1", - "keccak_builtin_applications": "1" + "keccak_builtin_applications": "1", + "data_availability": { + "l1_gas": "123", + "l1_data_gas": "456" + } } } } @@ -409,8 +423,8 @@ class ProviderTest { val provider = JsonRpcProvider(rpcUrl, httpService) val receipt = provider.getTransactionReceipt(Felt.fromHex("0x333198614194ae5b5ef921e63898a592de5e9f4d7b6e04745093da88b429f2a")).send() - assertTrue(receipt is PendingTransactionReceipt) - assertTrue(receipt is PendingInvokeTransactionReceipt) + assertTrue(receipt is InvokeTransactionReceipt) + assertTrue(receipt.isPending) assertEquals(PriceUnit.FRI, receipt.actualFee.unit) } @@ -471,7 +485,11 @@ class ProviderTest { "ec_op_builtin_applications": "123", "ecdsa_builtin_applications": "789", "bitwise_builtin_applications": "1", - "keccak_builtin_applications": "1" + "keccak_builtin_applications": "1", + "data_availability": { + "l1_gas": "123", + "l1_data_gas": "456" + } }, "message_hash": "0x8000000000000110000000000000000000000000000000000000011111111111" } @@ -485,7 +503,9 @@ class ProviderTest { val response = request.send() assertNotNull(response) - assertTrue(response is ProcessedTransactionReceipt) + assertTrue(response is L1HandlerTransactionReceipt) + assertTrue(response.hasBlockInfo) + assertFalse(response.isPending) assertEquals(PriceUnit.WEI, response.actualFee.unit) } @@ -549,7 +569,9 @@ class ProviderTest { @Test fun `get deploy account transaction receipt`() { val receipt = provider.getTransactionReceipt(deployAccountTransactionHash).send() - assertTrue(receipt is ProcessedDeployAccountTransactionReceipt) + assertTrue(receipt is DeployAccountTransactionReceipt) + assertTrue(receipt.hasBlockInfo) + assertFalse(receipt.isPending) } // TODO (#364): Enable this test once declare transaction conforms to the spec on devnet side. @@ -675,7 +697,7 @@ class ProviderTest { assertNotEquals(0, blockNumber) assertNotEquals(Felt.ZERO, blockHash) - val getBlockResponse = provider.getBlockWithTxHashes(blockNumber).send() as BlockWithTransactionHashesResponse + val getBlockResponse = provider.getBlockWithTxHashes(blockNumber).send() as ProcessedBlockWithTransactionHashes val expectedHash = getBlockResponse.blockHash assertEquals(expectedHash, blockHash) @@ -799,7 +821,13 @@ class ProviderTest { "price_in_wei": "0x2137", "price_in_fri": "0x1234" }, - "starknet_version": "0.12.3", + "l1_data_gas_price": + { + "price_in_wei": "0x789", + "price_in_fri": "0x123" + }, + "l1_da_mode": "BLOB", + "starknet_version": "0.13.1", "transactions": [ { "transaction_hash": "0x01", @@ -834,7 +862,7 @@ class ProviderTest { val request = provider.getBlockWithTxs(BlockTag.PENDING) val response = request.send() - assertTrue(response is PendingBlockWithTransactionsResponse) + assertTrue(response is PendingBlockWithTransactions) } @Test @@ -842,7 +870,9 @@ class ProviderTest { val request = provider.getBlockWithTxs(BlockTag.LATEST) val response = request.send() - assertTrue(response is BlockWithTransactionsResponse) + assertTrue(response is ProcessedBlockWithTransactions) + val block = response as ProcessedBlockWithTransactions + assertEquals(BlockStatus.ACCEPTED_ON_L2, block.status) } @Test @@ -852,7 +882,7 @@ class ProviderTest { val request = provider.getBlockWithTxs(blockHash) val response = request.send() - assertTrue(response is BlockWithTransactionsResponse) + assertTrue(response is ProcessedBlockWithTransactions) } @Test @@ -862,7 +892,154 @@ class ProviderTest { val request = provider.getBlockWithTxs(blockNumber) val response = request.send() - assertTrue(response is BlockWithTransactionsResponse) + assertTrue(response is ProcessedBlockWithTransactions) + } + + @Test + fun `get pending block with transaction receipts`() { + // TODO (#304): We should also test for 'pending' tag, but atm they are not supported in devnet + val mockedResponse = """ + { + "id":0, + "jsonrpc":"2.0", + "result":{ + "parent_hash": "0x123", + "timestamp": 7312, + "sequencer_address": "0x1234", + "l1_gas_price": + { + "price_in_wei": "0x2137", + "price_in_fri": "0x1234" + }, + "l1_data_gas_price": + { + "price_in_wei": "0x789", + "price_in_fri": "0x123" + }, + "l1_da_mode": "BLOB", + "starknet_version": "0.13.1", + "transactions": [ + { + "transaction": + { + "transaction_hash": "0x01", + "class_hash": "0x98", + "version": "0x0", + "type": "DEPLOY", + "max_fee": "0x1", + "signature": [], + "nonce": "0x1", + "contract_address_salt": "0x0", + "constructor_calldata": [] + }, + "receipt": + { + "actual_fee": { + "amount": "0x244adfc7e22", + "unit": "WEI" + }, + "block_hash": "0x4e782152c52c8637e03df60048deb4f6adf122ef37cf53eeb72322a4b9c9c52", + "contract_address": "0x20f8c63faff27a0c5fe8a25dc1635c40c971bf67b8c35c6089a998649dfdfcb", + "transaction_hash": "0x1a9d9e311ff31e27b20a7919bec6861dd6b603d72b7e8df9900cd7603200d0b", + "finality_status": "ACCEPTED_ON_L1", + "execution_status": "SUCCEEDED", + "block_number": 264715, + "type": "DEPLOY", + "events": + [], + "messages_sent": + [], + "execution_resources": + { + "steps": "999", + "data_availability": { + "l1_gas": "123", + "l1_data_gas": "456" + } + } + } + }, + { + "transaction": + { + "transaction_hash": "0x02", + "class_hash": "0x99", + "version": "0x1", + "max_fee": "0x1", + "type": "DECLARE", + "sender_address": "0x15", + "signature": [], + "nonce": "0x1" + }, + "receipt": + { + "actual_fee": { + "amount": "0x244adfc7e22", + "unit": "WEI" + }, + "block_hash": "0x4e782152c52c8637e03df60048deb4f6adf122ef37cf53eeb72322a4b9c9c52", + "transaction_hash": "0x1a9d9e311ff31e27b20a7919bec6861dd6b603d72b7e8df9900cd7603200d0b", + "finality_status": "ACCEPTED_ON_L1", + "execution_status": "SUCCEEDED", + "block_number": 264715, + "type": "DECLARE", + "events": + [], + "messages_sent": + [], + "execution_resources": + { + "steps": "999", + "data_availability": { + "l1_gas": "123", + "l1_data_gas": "456" + } + } + } + } + ] + } + } + """.trimIndent() + val httpService = mock { + on { send(any()) } doReturn HttpResponse(true, 200, mockedResponse) + } + val provider = JsonRpcProvider(rpcUrl, httpService) + + val request = provider.getBlockWithReceipts(BlockTag.PENDING) + val response = request.send() + + assertTrue(response is PendingBlockWithReceipts) + } + + @Test + fun `get block with transaction receipts with block tag`() { + val request = provider.getBlockWithReceipts(BlockTag.LATEST) + val response = request.send() + + assertTrue(response is ProcessedBlockWithReceipts) + val block = response as ProcessedBlockWithReceipts + assertEquals(BlockStatus.ACCEPTED_ON_L2, block.status) + } + + @Test + fun `get block with transaction receipts with block hash`() { + val blockHash = provider.getBlockHashAndNumber().send().blockHash + + val request = provider.getBlockWithReceipts(blockHash) + val response = request.send() + + assertTrue(response is ProcessedBlockWithReceipts) + } + + @Test + fun `get block with transaction receipts with block number`() { + val blockNumber = provider.getBlockNumber().send() + + val request = provider.getBlockWithReceipts(blockNumber) + val response = request.send() + + assertTrue(response is ProcessedBlockWithReceipts) } @Test @@ -881,7 +1058,13 @@ class ProviderTest { "price_in_wei": "0x2137", "price_in_fri": "0x1234" }, - "starknet_version": "0.13.0", + "l1_data_gas_price": + { + "price_in_wei": "0x789", + "price_in_fri": "0x123" + }, + "l1_da_mode": "BLOB", + "starknet_version": "0.13.1", "transactions": [ "0x01", "0x02" @@ -897,7 +1080,7 @@ class ProviderTest { val request = provider.getBlockWithTxHashes(BlockTag.PENDING) val response = request.send() - assertTrue(response is PendingBlockWithTransactionHashesResponse) + assertTrue(response is PendingBlockWithTransactionHashes) } @Test @@ -905,7 +1088,9 @@ class ProviderTest { val request = provider.getBlockWithTxHashes(BlockTag.LATEST) val response = request.send() - assertTrue(response is BlockWithTransactionHashesResponse) + assertTrue(response is ProcessedBlockWithTransactionHashes) + val block = response as ProcessedBlockWithTransactionHashes + assertEquals(BlockStatus.ACCEPTED_ON_L2, block.status) } @Test @@ -915,7 +1100,7 @@ class ProviderTest { val request = provider.getBlockWithTxHashes(blockHash) val response = request.send() - assertTrue(response is BlockWithTransactionHashesResponse) + assertTrue(response is ProcessedBlockWithTransactionHashes) } @Test @@ -925,7 +1110,7 @@ class ProviderTest { val request = provider.getBlockWithTxHashes(blockNumber) val response = request.send() - assertTrue(response is BlockWithTransactionHashesResponse) + assertTrue(response is ProcessedBlockWithTransactionHashes) } @Test diff --git a/lib/src/test/kotlin/starknet/provider/response/JsonRpcResponseTest.kt b/lib/src/test/kotlin/starknet/provider/response/JsonRpcResponseTest.kt index 769b8a864..72392b44a 100644 --- a/lib/src/test/kotlin/starknet/provider/response/JsonRpcResponseTest.kt +++ b/lib/src/test/kotlin/starknet/provider/response/JsonRpcResponseTest.kt @@ -29,6 +29,8 @@ class JsonRpcResponseTest { "unknown_primitive": "value", "gas_consumed": "0x1234", "gas_price": "0x5678", + "data_gas_consumed": "0xabc", + "data_gas_price": "0x789", "overall_fee": "0x9abc", "unknown_object": {"key_1": "value_1", "key_2": "value_2"}, "unit": "FRI", diff --git a/lib/src/test/kotlin/starknet/utils/DevnetClient.kt b/lib/src/test/kotlin/starknet/utils/DevnetClient.kt index 8a9dcd8a8..39a862218 100644 --- a/lib/src/test/kotlin/starknet/utils/DevnetClient.kt +++ b/lib/src/test/kotlin/starknet/utils/DevnetClient.kt @@ -245,7 +245,7 @@ class DevnetClient( fun declareContract( contractName: String, - maxFee: Felt = Felt(1000000000000000), + maxFee: Felt = Felt(5000000000000000), accountName: String = "__default__", ): DeclareContractResult { val params = listOf( @@ -312,7 +312,7 @@ class DevnetClient( constructorCalldata: List = emptyList(), salt: Felt? = null, unique: Boolean = false, - maxFeeDeclare: Felt = Felt(1000000000000000), + maxFeeDeclare: Felt = Felt(5000000000000000), maxFeeDeploy: Felt = Felt(1000000000000000), accountName: String = "__default__", ): DeployContractResult {