Skip to content

Commit

Permalink
Use different versioning for fee estimation (#230)
Browse files Browse the repository at this point in the history
  • Loading branch information
THenry14 authored Jan 23, 2023
1 parent 6401bec commit 8afac6a
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 12 deletions.
2 changes: 1 addition & 1 deletion androiddemo/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ dependencies {
implementation("androidx.appcompat:appcompat:1.4.2")
implementation("com.google.android.material:material:1.6.1")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("com.swmansion.starknet:starknet:0.4.0@aar")
implementation("com.swmansion.starknet:starknet:0.5.0@aar")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.3")
androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
Expand Down
2 changes: 1 addition & 1 deletion javademo/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
}

dependencies {
implementation("com.swmansion.starknet:starknet:0.4.0")
implementation("com.swmansion.starknet:starknet:0.5.0")
}

application {
Expand Down
2 changes: 1 addition & 1 deletion lib/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import org.jetbrains.dokka.gradle.DokkaTask

version = "0.4.0"
version = "0.5.0"
group = "com.swmansion.starknet"

plugins {
Expand Down
13 changes: 10 additions & 3 deletions lib/src/main/kotlin/com/swmansion/starknet/account/Account.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ interface Account {
*
* @param call a call to be signed
* @param params additional execution parameters for the transaction
* @param forFeeEstimate when set to `true`, it changes the version to `2^128+version` so the signed transaction can only be used for fee estimation
* @return signed invoke function payload
*/
fun sign(call: Call, params: ExecutionParams): InvokeTransactionPayload {
return sign(listOf(call), params)
fun sign(call: Call, params: ExecutionParams, forFeeEstimate: Boolean = false): InvokeTransactionPayload {
return sign(listOf(call), params, forFeeEstimate)
}

/**
Expand All @@ -32,9 +33,10 @@ interface Account {
*
* @param calls a list of calls to be signed
* @param params additional execution parameters for the transaction
* @param forFeeEstimate when set to `true`, it changes the version to `2^128+version` so the signed transaction can only be used for fee estimation
* @return signed invoke function payload
*/
fun sign(calls: List<Call>, params: ExecutionParams): InvokeTransactionPayload
fun sign(calls: List<Call>, params: ExecutionParams, forFeeEstimate: Boolean = false): InvokeTransactionPayload

/**
* Sign deploy account transaction.
Expand All @@ -44,13 +46,16 @@ interface Account {
* @param classHash hash of the contract that will be deployed. Has to be declared first!
* @param calldata constructor calldata for the contract deployment
* @param salt salt used to calculate address of the new contract
* @param maxFee max fee to be consumed by this transaction
* @param forFeeEstimate when set to `true`, it changes the version to `2^128+version` so the signed transaction can only be used for fee estimation
* @return signed deploy account payload
*/
fun signDeployAccount(
classHash: Felt,
calldata: Calldata,
salt: Felt,
maxFee: Felt,
forFeeEstimate: Boolean = false,
): DeployAccountTransactionPayload

/**
Expand All @@ -61,12 +66,14 @@ interface Account {
* @param contractDefinition a definition of the contract to be declared
* @param classHash a class hash of the contract to be declared
* @param params additional execution parameters for the transaction
* @param forFeeEstimate when set to `true`, it changes the version to `2^128+version` so the signed transaction can only be used for fee estimation
* @return signed declare transaction payload
*/
fun signDeclare(
contractDefinition: ContractDefinition,
classHash: Felt,
params: ExecutionParams,
forFeeEstimate: Boolean = false,
): DeclareTransactionPayload

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.swmansion.starknet.provider.Provider
import com.swmansion.starknet.provider.Request
import com.swmansion.starknet.signer.Signer
import com.swmansion.starknet.signer.StarkCurveSigner
import java.math.BigInteger

/**
* Standard account used in StarkNet.
Expand All @@ -23,6 +24,7 @@ class StandardAccount(
private val provider: Provider,
) : Account {
private val version = Felt.ONE
private val estimateVersion: BigInteger = BigInteger.valueOf(2).pow(128).add(version.value)

/**
* @param provider a provider used to interact with StarkNet
Expand All @@ -35,14 +37,19 @@ class StandardAccount(
provider,
)

override fun sign(calls: List<Call>, params: ExecutionParams): InvokeTransactionPayload {
override fun sign(calls: List<Call>, params: ExecutionParams, forFeeEstimate: Boolean): InvokeTransactionPayload {
val calldata = callsToExecuteCalldata(calls)
val signVersion = when (forFeeEstimate) {
true -> Felt(estimateVersion)
false -> version
}
val tx = TransactionFactory.makeInvokeTransaction(
senderAddress = address,
calldata = calldata,
chainId = provider.chainId,
nonce = params.nonce,
maxFee = params.maxFee,
version = signVersion,
)

val signedTransaction = tx.copy(signature = signer.signTransaction(tx))
Expand All @@ -55,15 +62,20 @@ class StandardAccount(
calldata: Calldata,
salt: Felt,
maxFee: Felt,
forFeeEstimate: Boolean,
): DeployAccountTransactionPayload {
val signVersion = when (forFeeEstimate) {
true -> Felt(estimateVersion)
false -> version
}
val tx = TransactionFactory.makeDeployAccountTransaction(
classHash = classHash,
contractAddress = address,
salt = salt,
calldata = calldata,
chainId = provider.chainId,
maxFee = maxFee,
version = version,
version = signVersion,
)
val signedTransaction = tx.copy(signature = signer.signTransaction(tx))

Expand All @@ -74,15 +86,20 @@ class StandardAccount(
contractDefinition: ContractDefinition,
classHash: Felt,
params: ExecutionParams,
forFeeEstimate: Boolean,
): DeclareTransactionPayload {
val signVersion = when (forFeeEstimate) {
true -> Felt(estimateVersion)
false -> version
}
val tx = TransactionFactory.makeDeclareTransaction(
contractDefinition = contractDefinition,
classHash = classHash,
senderAddress = address,
chainId = provider.chainId,
nonce = params.nonce,
maxFee = params.maxFee,
version = version,
version = signVersion,
)
val signedTransaction = tx.copy(signature = signer.signTransaction(tx))

Expand Down Expand Up @@ -113,7 +130,7 @@ class StandardAccount(

private fun buildEstimateFeeRequest(calls: List<Call>, nonce: Felt): Request<EstimateFeeResponse> {
val executionParams = ExecutionParams(nonce = nonce, maxFee = Felt.ZERO)
val payload = sign(calls, executionParams)
val payload = sign(calls, executionParams, true)

val signedTransaction = TransactionFactory.makeInvokeTransaction(
senderAddress = payload.senderAddress,
Expand All @@ -122,6 +139,7 @@ class StandardAccount(
nonce = nonce,
maxFee = payload.maxFee,
signature = payload.signature,
version = payload.version,
)

return provider.getEstimateFee(signedTransaction.toPayload(), BlockTag.LATEST)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ data class InvokeTransactionV1(
maxFee = maxFee,
nonce = nonce,
senderAddress = senderAddress,
version = version,
)
}

Expand Down Expand Up @@ -306,16 +307,17 @@ object TransactionFactory {
nonce: Felt,
maxFee: Felt = Felt.ZERO,
signature: Signature = emptyList(),
version: Felt,
): InvokeTransactionV1 {
val hash = TransactionHashCalculator.calculateInvokeTxHash(
contractAddress = senderAddress,
calldata = calldata,
chainId = chainId,
version = INVOKE_VERSION,
version = version,
nonce = nonce,
maxFee = maxFee,
)
return InvokeTransactionV1(calldata, senderAddress, hash, maxFee, INVOKE_VERSION, signature, nonce)
return InvokeTransactionV1(calldata, senderAddress, hash, maxFee, version, signature, nonce)
}

@JvmStatic
Expand Down
39 changes: 39 additions & 0 deletions lib/src/test/kotlin/starknet/account/StandardAccountTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.swmansion.starknet.data.types.transactions.DeployAccountTransaction
import com.swmansion.starknet.data.types.transactions.TransactionFactory
import com.swmansion.starknet.data.types.transactions.TransactionStatus
import com.swmansion.starknet.provider.Provider
import com.swmansion.starknet.provider.exceptions.RequestFailedException
import com.swmansion.starknet.provider.gateway.GatewayProvider
import com.swmansion.starknet.provider.rpc.JsonRpcProvider
import com.swmansion.starknet.signer.StarkCurveSigner
Expand All @@ -19,6 +20,7 @@ import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import starknet.utils.ContractDeployer
import starknet.utils.DevnetClient
import java.math.BigInteger
import java.nio.file.Path
import kotlin.io.path.readText

Expand Down Expand Up @@ -376,7 +378,10 @@ class StandardAccountTest {
salt = salt,
calldata = calldata,
maxFee = Felt.ZERO,
forFeeEstimate = true,
)
assertEquals(payloadForFeeEstimation.version, Felt(BigInteger("340282366920938463463374607431768211457")))

val feePayload = provider.getEstimateFee(payloadForFeeEstimation).send()
assertTrue(feePayload.overallFee.value > Felt.ONE.value)
}
Expand Down Expand Up @@ -435,4 +440,38 @@ class StandardAccountTest {
val receipt = provider.getTransactionReceipt(result.transactionHash).send()
assertEquals(TransactionStatus.ACCEPTED_ON_L2, receipt.status)
}

@ParameterizedTest
@MethodSource("getProviders")
fun `send transaction signed for fee estimation`(provider: Provider) {
val privateKey = Felt(11111)
val publicKey = StarknetCurve.getPublicKey(privateKey)

val classHash = accountClassHash
val salt = Felt.ONE
val calldata = listOf(publicKey)
val address = ContractAddressCalculator.calculateAddressFromHash(
classHash = classHash,
calldata = calldata,
salt = salt,
)

val account = StandardAccount(
address,
privateKey,
provider,
)
val payloadForFeeEstimation = account.signDeployAccount(
classHash = classHash,
salt = salt,
calldata = calldata,
maxFee = Felt.ZERO,
forFeeEstimate = true,
)
assertEquals(payloadForFeeEstimation.version, Felt(BigInteger("340282366920938463463374607431768211457")))

assertThrows(RequestFailedException::class.java) {
provider.deployAccount(payloadForFeeEstimation).send()
}
}
}
2 changes: 2 additions & 0 deletions lib/src/test/kotlin/starknet/data/types/TransactionsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ internal class TransactionsTest {
chainId = StarknetChainId.TESTNET,
nonce = Felt.ZERO,
maxFee = Felt.ZERO,
version = INVOKE_VERSION,
)

assertEquals(Felt.fromHex("0x22294fe217f962c39e4cb694a5db3f71e1132988451a9b2abc2d2ea8512088e"), tx1.hash)
Expand Down Expand Up @@ -48,6 +49,7 @@ internal class TransactionsTest {
chainId = StarknetChainId.TESTNET,
nonce = Felt.ZERO,
maxFee = Felt(BigInteger("100000000")),
version = INVOKE_VERSION,
)

assertEquals(Felt.fromHex("0xff63c84949d3ab0ced753c227528493dea3dc4680c65c1facb7f86ae0472df"), tx2.hash)
Expand Down

0 comments on commit 8afac6a

Please sign in to comment.