diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 356d5a37e..fe08cff99 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -16,7 +16,7 @@ jobs: runs-on: ${{ matrix.os }} env: - DEVNET_SHA: 1bd447d8ac8c2fb0a3eaf2d54512671f4a16c7ba + DEVNET_SHA: 55191ee549b33ccbb0bc9d20dd929e39832a5ea5 steps: - uses: actions/checkout@v3 with: 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 7ed3969ad..e02be5d8b 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/account/Account.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/account/Account.kt @@ -23,8 +23,8 @@ interface Account { * @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 transaction version 1 payload */ - fun sign(call: Call, params: ExecutionParams, forFeeEstimate: Boolean): InvokeTransactionV1Payload { - return sign(listOf(call), params, forFeeEstimate) + fun signV1(call: Call, params: ExecutionParams, forFeeEstimate: Boolean): InvokeTransactionV1Payload { + return signV1(listOf(call), params, forFeeEstimate) } /** @@ -37,8 +37,8 @@ interface Account { * @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 transaction version 3 payload */ - fun sign(call: Call, params: ExecutionParamsV3, forFeeEstimate: Boolean): InvokeTransactionV3Payload { - return sign(listOf(call), params, forFeeEstimate) + fun signV3(call: Call, params: InvokeParamsV3, forFeeEstimate: Boolean): InvokeTransactionV3Payload { + return signV3(listOf(call), params, forFeeEstimate) } /** @@ -50,8 +50,8 @@ interface Account { * @param params additional execution parameters for the transaction * @return signed invoke transaction version 1 payload */ - fun sign(call: Call, params: ExecutionParams): InvokeTransactionV1Payload { - return sign(listOf(call), params, false) + fun signV1(call: Call, params: ExecutionParams): InvokeTransactionV1Payload { + return signV1(listOf(call), params, false) } /** @@ -63,8 +63,8 @@ interface Account { * @param params additional execution parameters for the transaction * @return signed invoke transaction version 3 payload */ - fun sign(call: Call, params: ExecutionParamsV3): InvokeTransactionV3Payload { - return sign(listOf(call), params, false) + fun signV3(call: Call, params: InvokeParamsV3): InvokeTransactionV3Payload { + return signV3(listOf(call), params, false) } /** @@ -77,7 +77,7 @@ interface Account { * @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 transaction version 1 payload */ - fun sign(calls: List, params: ExecutionParams, forFeeEstimate: Boolean): InvokeTransactionV1Payload + fun signV1(calls: List, params: ExecutionParams, forFeeEstimate: Boolean): InvokeTransactionV1Payload /** * Sign multiple calls as a single version 3 invoke transaction. @@ -89,7 +89,7 @@ interface Account { * @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 transaction version 3 payload */ - fun sign(calls: List, params: ExecutionParamsV3, forFeeEstimate: Boolean): InvokeTransactionV3Payload + fun signV3(calls: List, params: InvokeParamsV3, forFeeEstimate: Boolean): InvokeTransactionV3Payload /** * Sign multiple calls as a single version 1 invoke transaction. @@ -100,8 +100,8 @@ interface Account { * @param params additional execution parameters for the transaction * @return signed invoke transaction version 1 payload */ - fun sign(calls: List, params: ExecutionParams): InvokeTransactionV1Payload { - return sign(calls, params, false) + fun signV1(calls: List, params: ExecutionParams): InvokeTransactionV1Payload { + return signV1(calls, params, false) } /** @@ -113,8 +113,8 @@ interface Account { * @param params additional execution parameters for the transaction * @return signed invoke transaction version 3 payload */ - fun sign(calls: List, params: ExecutionParamsV3): InvokeTransactionV3Payload { - return sign(calls, params, false) + fun signV3(calls: List, params: InvokeParamsV3): InvokeTransactionV3Payload { + return signV3(calls, params, false) } /** @@ -130,7 +130,7 @@ interface Account { * @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( + fun signDeployAccountV1( classHash: Felt, calldata: Calldata, salt: Felt, @@ -151,7 +151,7 @@ interface Account { * @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( + fun signDeployAccountV3( classHash: Felt, calldata: Calldata, salt: Felt, @@ -160,7 +160,7 @@ interface Account { ): DeployAccountTransactionV3Payload /** - * Sign deploy account transaction. + * Sign version 1 deploy account transaction. * * Sign a deploy account transaction that requires prefunding deployed address. * @@ -170,13 +170,13 @@ interface Account { * @param maxFee max fee to be consumed by this transaction * @return signed deploy account payload */ - fun signDeployAccount( + fun signDeployAccountV1( classHash: Felt, calldata: Calldata, salt: Felt, maxFee: Felt, ): DeployAccountTransactionV1Payload { - return signDeployAccount(classHash, calldata, salt, maxFee, Felt.ZERO, false) + return signDeployAccountV1(classHash, calldata, salt, maxFee, Felt.ZERO, false) } /** @@ -190,7 +190,7 @@ interface Account { * @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( + fun signDeployAccountV3( classHash: Felt, calldata: Calldata, salt: Felt, @@ -201,7 +201,7 @@ interface Account { nonce = Felt.ZERO, l1ResourceBounds = l1ResourceBounds, ) - return signDeployAccount(classHash, calldata, salt, params, forFeeEstimate) + return signDeployAccountV3(classHash, calldata, salt, params, forFeeEstimate) } /** @@ -215,7 +215,7 @@ interface Account { * @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( + fun signDeclareV1( contractDefinition: Cairo0ContractDefinition, classHash: Felt, params: ExecutionParams, @@ -233,7 +233,7 @@ interface Account { * @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( + fun signDeclareV2( sierraContractDefinition: Cairo1ContractDefinition, casmContractDefinition: CasmContractDefinition, params: ExecutionParams, @@ -251,7 +251,7 @@ interface Account { * @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( + fun signDeclareV3( sierraContractDefinition: Cairo1ContractDefinition, casmContractDefinition: CasmContractDefinition, params: DeclareParamsV3, @@ -284,7 +284,7 @@ interface Account { * @param maxFee a max fee to pay for the transaction. * @return Invoke function response, containing transaction hash. */ - fun execute(calls: List, maxFee: Felt): Request + fun executeV1(calls: List, maxFee: Felt): Request /** * Execute a list of calls using version 3 invoke transaction. @@ -300,18 +300,18 @@ interface Account { /** * Execute single call using version 1 invoke transaction. * - * Execute single call on starknet. + * Execute single call on Starknet. * * @param call a call to be executed. * @param maxFee a max fee to pay for the transaction. * @return Invoke function response, containing transaction hash. */ - fun execute(call: Call, maxFee: Felt): Request + fun executeV1(call: Call, maxFee: Felt): Request /** * Execute single call using version 3 invoke transaction. * - * Execute single call on starknet. + * Execute single call on Starknet. * * @param call a call to be executed. * @param l1ResourceBounds L1 resource bounds for the transaction. @@ -325,7 +325,7 @@ interface Account { * @param calls a list of calls to be executed. * @return Invoke function response, containing transaction hash. */ - fun execute(calls: List): Request + fun executeV1(calls: List): Request /** * Execute a list of calls with automatically estimated fee using version 3 invoke transaction. @@ -341,7 +341,7 @@ interface Account { * @param call a call to be executed. * @return Invoke function response, containing transaction hash. */ - fun execute(call: Call): Request + fun executeV1(call: Call): Request /** * Execute single call with automatically estimated fee using version 3 invoke transaction. @@ -354,50 +354,60 @@ interface Account { /** * Estimate fee for a call as a version 1 invoke transaction. * - * Estimate fee for a signed call on starknet. + * Estimate fee for a signed call on Starknet. + * + * @param call a call used to estimate a fee. + * @return Field value representing estimated fee. + */ + fun estimateFeeV1(call: Call): Request> + + /** + * Estimate fee for a call as a version 3 invoke transaction. + * + * Estimate fee for a signed call on Starknet. * * @param call a call used to estimate a fee. * @return Field value representing estimated fee. */ - fun estimateFee(call: Call): Request> + fun estimateFeeV3(call: Call): Request> /** * Estimate fee for a call as a version 1 invoke transaction. * - * Estimate fee for a signed call on starknet. + * Estimate fee for a signed call on Starknet. * * @param call a call used to estimate a fee. - * @param simulationFlags a set of simulation flags used to estimate a fee. + * @param skipValidate when set to `true`, the validation part of the transaction is skipped. * @return Field value representing estimated fee. */ - fun estimateFee(call: Call, simulationFlags: Set): Request> + fun estimateFeeV1(call: Call, skipValidate: Boolean): Request> /** * Estimate fee for a call as a version 3 invoke transaction. * - * Estimate fee for a signed call on starknet. + * Estimate fee for a signed call on Starknet. * * @param call a call used to estimate a fee. - * @param simulationFlags a set of simulation flags used to estimate a fee. + * @param skipValidate when set to `true`, the validation part of the transaction is skipped. * @return Field value representing estimated fee. */ - fun estimateFeeV3(call: Call, simulationFlags: Set): Request> + fun estimateFeeV3(call: Call, skipValidate: Boolean): Request> /** * Estimate fee for a call as a version 1 invoke transaction. * - * Estimate fee for a signed call on starknet for specified block tag. + * Estimate fee for a signed call on Starknet for specified block tag. * * @param call a call used to estimate a fee. * @param blockTag a tag of the block in respect to what the query will be made. * @return Field value representing estimated fee. */ - fun estimateFee(call: Call, blockTag: BlockTag): Request> + fun estimateFeeV1(call: Call, blockTag: BlockTag): Request> /** * Estimate fee for a call as a version 3 invoke transaction. * - * Estimate fee for a signed call on starknet for specified block tag. + * Estimate fee for a signed call on Starknet for specified block tag. * * @param call a call used to estimate a fee. * @param blockTag a tag of the block in respect to what the query will be made. @@ -406,43 +416,43 @@ interface Account { fun estimateFeeV3(call: Call, blockTag: BlockTag): Request> /** - * Estimate fee for a call. + * Estimate fee for a call as a version 1 invoke transaction. * - * Estimate fee for a signed call on starknet for specified block tag. + * Estimate fee for a signed call on Starknet for specified block tag. * * @param call a call used to estimate a fee. * @param blockTag a tag of the block in respect to what the query will be made. - * @param simulationFlags a set of simulation flags used to estimate a fee. + * @param skipValidate when set to `true`, the validation part of the transaction is skipped. * @return Field value representing estimated fee. */ - fun estimateFee(call: Call, blockTag: BlockTag, simulationFlags: Set): Request> + fun estimateFeeV1(call: Call, blockTag: BlockTag, skipValidate: Boolean): Request> /** * Estimate fee for a call as a version 3 invoke transaction. * - * Estimate fee for a signed call on starknet for specified block tag. + * Estimate fee for a signed call on Starknet for specified block tag. * * @param call a call used to estimate a fee. * @param blockTag a tag of the block in respect to what the query will be made. - * @param simulationFlags a set of simulation flags used to estimate a fee. + * @param skipValidate when set to `true`, the validation part of the transaction is skipped. * @return Field value representing estimated fee. */ - fun estimateFeeV3(call: Call, blockTag: BlockTag, simulationFlags: Set): Request> + fun estimateFeeV3(call: Call, blockTag: BlockTag, skipValidate: Boolean): Request> /** * Estimate fee for a list of calls as a version 1 invoke transaction. * - * Estimate fee for a signed list of calls on starknet. + * Estimate fee for a signed list of calls on Starknet. * * @param calls a list of calls used to estimate a fee. * @return estimated fee as field value. */ - fun estimateFee(calls: List): Request> + fun estimateFeeV1(calls: List): Request> /** * Estimate fee for a list of calls as a version 3 invoke transaction. * - * Estimate fee for a signed list of calls on starknet. + * Estimate fee for a signed list of calls on Starknet. * * @param calls a list of calls used to estimate a fee. * @return estimated fee as field value. @@ -452,40 +462,40 @@ interface Account { /** * Estimate fee for a list of calls as a version 1 invoke transaction. * - * Estimate fee for a signed list of calls on starknet. + * Estimate fee for a signed list of calls on Starknet. * * @param calls a list of calls used to estimate a fee. - * @param simulationFlags a set of simulation flags used to estimate a fee. + * @param skipValidate when set to `true`, the validation part of the transaction is skipped. * @return estimated fee as field value. */ - fun estimateFee(calls: List, simulationFlags: Set): Request> + fun estimateFeeV1(calls: List, skipValidate: Boolean): Request> /** * Estimate fee for a list of calls as a version 3 invoke transaction. * - * Estimate fee for a signed list of calls on starknet. + * Estimate fee for a signed list of calls on Starknet. * * @param calls a list of calls used to estimate a fee. - * @param simulationFlags a set of simulation flags used to estimate a fee. + * @param skipValidate when set to `true`, the validation part of the transaction is skipped. * @return estimated fee as field value. */ - fun estimateFeeV3(calls: List, simulationFlags: Set): Request> + fun estimateFeeV3(calls: List, skipValidate: Boolean): Request> /** * Estimate fee for a list of calls as a version 1 invoke transaction. * - * Estimate fee for a signed list of calls on starknet. + * Estimate fee for a signed list of calls on Starknet. * * @param calls a list of calls used to estimate a fee. * @param blockTag a tag of the block in respect to what the query will be made. * @return estimated fee as field value. */ - fun estimateFee(calls: List, blockTag: BlockTag): Request> + fun estimateFeeV1(calls: List, blockTag: BlockTag): Request> /** * Estimate fee for a list of calls. * - * Estimate fee for a signed list of calls on starknet. + * Estimate fee for a signed list of calls on Starknet. * * @param calls a list of calls used to estimate a fee. * @param blockTag a tag of the block in respect to what the query will be made. @@ -496,33 +506,33 @@ interface Account { /** * Estimate fee for a list of calls using version 3 invoke transaction. * - * Estimate fee for a signed list of calls on starknet. + * Estimate fee for a signed list of calls on Starknet. * * @param calls a list of calls used to estimate a fee. * @param blockTag a tag of the block in respect to what the query will be made. - * @param simulationFlags a set of simulation flags used to estimate a fee. + * @param skipValidate when set to `true`, the validation part of the transaction is skipped. * @return estimated fee as field value. */ - fun estimateFee( + fun estimateFeeV1( calls: List, blockTag: BlockTag, - simulationFlags: Set, + skipValidate: Boolean, ): Request> /** * Estimate fee for a list of calls. * - * Estimate fee for a signed list of calls on starknet. + * Estimate fee for a signed list of calls on Starknet. * * @param calls a list of calls used to estimate a fee. * @param blockTag a tag of the block in respect to what the query will be made. - * @param simulationFlags a set of simulation flags used to estimate a fee. + * @param skipValidate when set to `true`, the validation part of the transaction is skipped. * @return estimated fee as field value. */ fun estimateFeeV3( calls: List, blockTag: BlockTag, - simulationFlags: Set, + skipValidate: Boolean, ): Request> /** 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 ffad66ea4..d32a10f42 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/account/StandardAccount.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/account/StandardAccount.kt @@ -33,9 +33,6 @@ class StandardAccount( .add(version.value) .toFelt } - private val defaultFeeEstimateSimulationFlags: Set by lazy { - setOf(SimulationFlagForEstimateFee.SKIP_VALIDATE) - } /** * @param provider a provider used to interact with Starknet @@ -49,7 +46,7 @@ class StandardAccount( cairoVersion, ) - override fun sign(calls: List, params: ExecutionParams, forFeeEstimate: Boolean): InvokeTransactionV1Payload { + override fun signV1(calls: List, params: ExecutionParams, forFeeEstimate: Boolean): InvokeTransactionV1Payload { val calldata = AccountCalldataTransformer.callsToExecuteCalldata(calls, cairoVersion) val signVersion = when (forFeeEstimate) { true -> estimateVersion(Felt.ONE) @@ -69,7 +66,7 @@ class StandardAccount( return signedTransaction.toPayload() } - override fun sign(calls: List, params: ExecutionParamsV3, forFeeEstimate: Boolean): InvokeTransactionV3Payload { + override fun signV3(calls: List, params: InvokeParamsV3, forFeeEstimate: Boolean): InvokeTransactionV3Payload { val calldata = AccountCalldataTransformer.callsToExecuteCalldata(calls, cairoVersion) val signVersion = when (forFeeEstimate) { true -> estimateVersion(Felt(3)) @@ -82,11 +79,6 @@ class StandardAccount( nonce = params.nonce, version = signVersion, resourceBounds = params.resourceBounds, - tip = params.tip, - paymasterData = params.paymasterData, - accountDeploymentData = params.accountDeploymentData, - nonceDataAvailabilityMode = params.nonceDataAvailabilityMode, - feeDataAvailabilityMode = params.feeDataAvailabilityMode, ) val signedTransaction = tx.copy(signature = signer.signTransaction(tx)) @@ -94,7 +86,7 @@ class StandardAccount( return signedTransaction.toPayload() } - override fun signDeployAccount( + override fun signDeployAccountV1( classHash: Felt, calldata: Calldata, salt: Felt, @@ -121,7 +113,7 @@ class StandardAccount( return signedTransaction.toPayload() } - override fun signDeployAccount( + override fun signDeployAccountV3( classHash: Felt, calldata: Calldata, salt: Felt, @@ -141,17 +133,13 @@ class StandardAccount( version = signVersion, nonce = params.nonce, resourceBounds = params.resourceBounds, - tip = params.tip, - paymasterData = params.paymasterData, - nonceDataAvailabilityMode = params.nonceDataAvailabilityMode, - feeDataAvailabilityMode = params.feeDataAvailabilityMode, ) val signedTransaction = tx.copy(signature = signer.signTransaction(tx)) return signedTransaction.toPayload() } - override fun signDeclare( + override fun signDeclareV1( contractDefinition: Cairo0ContractDefinition, classHash: Felt, params: ExecutionParams, @@ -175,7 +163,7 @@ class StandardAccount( return signedTransaction.toPayload() } - override fun signDeclare( + override fun signDeclareV2( sierraContractDefinition: Cairo1ContractDefinition, casmContractDefinition: CasmContractDefinition, params: ExecutionParams, @@ -199,7 +187,7 @@ class StandardAccount( return signedTransaction.toPayload() } - override fun signDeclare( + override fun signDeclareV3( sierraContractDefinition: Cairo1ContractDefinition, casmContractDefinition: CasmContractDefinition, params: DeclareParamsV3, @@ -216,12 +204,7 @@ class StandardAccount( nonce = params.nonce, version = signVersion, resourceBounds = params.resourceBounds, - tip = params.tip, - paymasterData = params.paymasterData, - accountDeploymentData = params.accountDeploymentData, casmContractDefinition = casmContractDefinition, - nonceDataAvailabilityMode = params.nonceDataAvailabilityMode, - feeDataAvailabilityMode = params.feeDataAvailabilityMode, ) val signedTransaction = tx.copy(signature = signer.signTransaction(tx)) @@ -277,10 +260,10 @@ class StandardAccount( throw e } - override fun execute(calls: List, maxFee: Felt): Request { + override fun executeV1(calls: List, maxFee: Felt): Request { return getNonce().compose { nonce -> val signParams = ExecutionParams(nonce = nonce, maxFee = maxFee) - val payload = sign(calls, signParams) + val payload = signV1(calls, signParams) return@compose provider.invokeFunction(payload) } @@ -288,40 +271,40 @@ class StandardAccount( override fun executeV3(calls: List, l1ResourceBounds: ResourceBounds): Request { return getNonce().compose { nonce -> - val signParams = ExecutionParamsV3( + val signParams = InvokeParamsV3( nonce = nonce, l1ResourceBounds = l1ResourceBounds, ) - val payload = sign(calls, signParams, false) + val payload = signV3(calls, signParams, false) return@compose provider.invokeFunction(payload) } } - override fun execute(calls: List): Request { - return estimateFee(calls).compose { estimateFee -> + override fun executeV1(calls: List): Request { + return estimateFeeV1(calls).compose { estimateFee -> val maxFee = estimateFee.first().toMaxFee() - execute(calls, maxFee) + executeV1(calls, maxFee) } } override fun executeV3(calls: List): Request { - return estimateFee(calls).compose { estimateFee -> + return estimateFeeV3(calls).compose { estimateFee -> val resourceBounds = estimateFee.first().toResourceBounds() executeV3(calls, resourceBounds.l1Gas) } } - override fun execute(call: Call, maxFee: Felt): Request { - return execute(listOf(call), maxFee) + override fun executeV1(call: Call, maxFee: Felt): Request { + return executeV1(listOf(call), maxFee) } override fun executeV3(call: Call, l1ResourceBounds: ResourceBounds): Request { return executeV3(listOf(call), l1ResourceBounds) } - override fun execute(call: Call): Request { - return execute(listOf(call)) + override fun executeV1(call: Call): Request { + return executeV1(listOf(call)) } override fun executeV3(call: Call): Request { @@ -336,100 +319,97 @@ class StandardAccount( override fun getNonce(blockNumber: Int) = provider.getNonce(address, blockNumber) - override fun estimateFee(call: Call): Request> { - return estimateFee(listOf(call)) + override fun estimateFeeV1(call: Call): Request> { + return estimateFeeV1(listOf(call)) } - override fun estimateFee(call: Call, simulationFlags: Set): Request> { - return estimateFee(listOf(call), simulationFlags) + override fun estimateFeeV3(call: Call): Request> { + return estimateFeeV3(listOf(call)) } - override fun estimateFee(call: Call, blockTag: BlockTag): Request> { - return estimateFee(listOf(call), blockTag) + override fun estimateFeeV1(call: Call, skipValidate: Boolean): Request> { + return estimateFeeV1(listOf(call), skipValidate) } - override fun estimateFee( - call: Call, - blockTag: BlockTag, - simulationFlags: Set, - ): Request> { - return estimateFee(listOf(call), blockTag, simulationFlags) + override fun estimateFeeV3(call: Call, skipValidate: Boolean): Request> { + return estimateFeeV3(listOf(call), skipValidate) } - override fun estimateFee(calls: List): Request> { - return estimateFee(calls, BlockTag.PENDING) + override fun estimateFeeV1(call: Call, blockTag: BlockTag): Request> { + return estimateFeeV1(listOf(call), blockTag) } - override fun estimateFeeV3(calls: List): Request> { - return estimateFeeV3(calls, BlockTag.PENDING, defaultFeeEstimateSimulationFlags) + override fun estimateFeeV3(call: Call, blockTag: BlockTag): Request> { + return estimateFeeV3(listOf(call), blockTag) } - override fun estimateFee( - calls: List, - simulationFlags: Set, + override fun estimateFeeV1( + call: Call, + blockTag: BlockTag, + skipValidate: Boolean, ): Request> { - return estimateFee(calls, BlockTag.PENDING, simulationFlags) + return estimateFeeV1(listOf(call), blockTag, skipValidate) } override fun estimateFeeV3( - calls: List, - simulationFlags: Set, + call: Call, + blockTag: BlockTag, + skipValidate: Boolean, ): Request> { - return estimateFeeV3(calls, BlockTag.PENDING, simulationFlags) + return estimateFeeV3(listOf(call), blockTag, skipValidate) } - override fun estimateFeeV3(calls: List, blockTag: BlockTag): Request> { - return estimateFeeV3(calls, blockTag) + override fun estimateFeeV1(calls: List): Request> { + return estimateFeeV1(calls, BlockTag.PENDING, false) } - override fun estimateFee(calls: List, blockTag: BlockTag): Request> { - return estimateFee(calls, blockTag, defaultFeeEstimateSimulationFlags) + override fun estimateFeeV3(calls: List): Request> { + return estimateFeeV3(calls, BlockTag.PENDING, false) } - override fun estimateFee( - calls: List, - blockTag: BlockTag, - simulationFlags: Set, - ): Request> { - return getNonce(blockTag).compose { nonce -> - val payload = buildEstimateFeePayload(calls, nonce) - return@compose provider.getEstimateFee(payload, blockTag, simulationFlags) - } + override fun estimateFeeV1(calls: List, skipValidate: Boolean): Request> { + return estimateFeeV1(calls, BlockTag.PENDING, skipValidate) } - override fun estimateFeeV3( - call: Call, - simulationFlags: Set, - ): Request> { - return estimateFeeV3(listOf(call), simulationFlags) + override fun estimateFeeV3(calls: List, skipValidate: Boolean): Request> { + return estimateFeeV3(calls, BlockTag.PENDING, skipValidate) } - override fun estimateFeeV3(call: Call, blockTag: BlockTag): Request> { - return estimateFeeV3(listOf(call), blockTag) + override fun estimateFeeV1(calls: List, blockTag: BlockTag): Request> { + return estimateFeeV1(calls, blockTag, false) } - override fun estimateFeeV3( - call: Call, + override fun estimateFeeV3(calls: List, blockTag: BlockTag): Request> { + return estimateFeeV3(calls, blockTag, false) + } + + override fun estimateFeeV1( + calls: List, blockTag: BlockTag, - simulationFlags: Set, + skipValidate: Boolean, ): Request> { - return estimateFeeV3(listOf(call), blockTag, simulationFlags) + return getNonce(blockTag).compose { nonce -> + val simulationFlags = prepareSimulationFlagsForFeeEstimate(skipValidate) + val payload = buildEstimateFeeV1Payload(calls, nonce) + return@compose provider.getEstimateFee(payload, blockTag, simulationFlags) + } } override fun estimateFeeV3( calls: List, blockTag: BlockTag, - simulationFlags: Set, + skipValidate: Boolean, ): Request> { return getNonce(blockTag).compose { nonce -> val payload = buildEstimateFeeV3Payload(calls, nonce) + val simulationFlags = prepareSimulationFlagsForFeeEstimate(skipValidate) return@compose provider.getEstimateFee(payload, blockTag, simulationFlags) } } - private fun buildEstimateFeePayload(calls: List, nonce: Felt): List { + private fun buildEstimateFeeV1Payload(calls: List, nonce: Felt): List { val executionParams = ExecutionParams(nonce = nonce, maxFee = Felt.ZERO) - val payload = sign(calls, executionParams, true) + val payload = signV1(calls, executionParams, true) val signedTransaction = TransactionFactory.makeInvokeV1Transaction( senderAddress = payload.senderAddress, @@ -444,11 +424,11 @@ class StandardAccount( } private fun buildEstimateFeeV3Payload(calls: List, nonce: Felt): List { - val executionParams = ExecutionParamsV3( + val executionParams = InvokeParamsV3( nonce = nonce, l1ResourceBounds = ResourceBounds.ZERO, ) - val payload = sign(calls, executionParams, false) + val payload = signV3(calls, executionParams, true) val signedTransaction = TransactionFactory.makeInvokeV3Transaction( senderAddress = payload.senderAddress, @@ -458,12 +438,15 @@ class StandardAccount( signature = payload.signature, version = payload.version, resourceBounds = payload.resourceBounds, - tip = payload.tip, - paymasterData = payload.paymasterData, - accountDeploymentData = payload.accountDeploymentData, - nonceDataAvailabilityMode = payload.nonceDataAvailabilityMode, - feeDataAvailabilityMode = payload.feeDataAvailabilityMode, ) return listOf(signedTransaction.toPayload()) } + + private fun prepareSimulationFlagsForFeeEstimate(skipValidate: Boolean): Set { + return if (skipValidate) { + setOf(SimulationFlagForEstimateFee.SKIP_VALIDATE) + } else { + emptySet() + } + } } diff --git a/lib/src/main/kotlin/com/swmansion/starknet/data/TransactionHashCalculator.kt b/lib/src/main/kotlin/com/swmansion/starknet/data/TransactionHashCalculator.kt index f2d2c1950..06ad3b174 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/data/TransactionHashCalculator.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/data/TransactionHashCalculator.kt @@ -48,7 +48,7 @@ object TransactionHashCalculator { nonceDataAvailabilityMode: DAMode, ): Felt { return Poseidon.poseidonHash( - *CommonTransanctionV3Fields( + *prepareCommonTransanctionV3Fields( txType = TransactionType.INVOKE, version = version, address = senderAddress, @@ -112,7 +112,7 @@ object TransactionHashCalculator { salt = salt, ) return Poseidon.poseidonHash( - *CommonTransanctionV3Fields( + *prepareCommonTransanctionV3Fields( txType = TransactionType.DEPLOY_ACCOUNT, version = version, address = contractAddress, @@ -192,7 +192,7 @@ object TransactionHashCalculator { nonceDataAvailabilityMode: DAMode, ): Felt { return Poseidon.poseidonHash( - *CommonTransanctionV3Fields( + *prepareCommonTransanctionV3Fields( txType = TransactionType.DECLARE, version = version, address = senderAddress, @@ -232,7 +232,7 @@ object TransactionHashCalculator { ) } - private fun CommonTransanctionV3Fields( + private fun prepareCommonTransanctionV3Fields( txType: TransactionType, version: Felt, address: Felt, @@ -250,19 +250,19 @@ object TransactionHashCalculator { address, Poseidon.poseidonHash( tip.toFelt, - *resourceBoundsForFee(resourceBounds).toList().toTypedArray(), + *prepareResourceBoundsForFee(resourceBounds).toList().toTypedArray(), ), Poseidon.poseidonHash(paymasterData), chainId.value.toFelt, nonce, - dataAvailabilityModes( + prepareDataAvailabilityModes( feeDataAvailabilityMode, nonceDataAvailabilityMode, ), ) } - private fun resourceBoundsForFee(resourceBounds: ResourceBoundsMapping): Pair { + private fun prepareResourceBoundsForFee(resourceBounds: ResourceBoundsMapping): Pair { val l1GasBound = l1GasPrefix.value.shiftLeft(64 + 128) .add(resourceBounds.l1Gas.maxAmount.value.shiftLeft(128)) .add(resourceBounds.l1Gas.maxPricePerUnit.value) @@ -275,7 +275,7 @@ object TransactionHashCalculator { return l1GasBound to l2GasBound } - private fun dataAvailabilityModes( + internal fun prepareDataAvailabilityModes( feeDataAvailabilityMode: DAMode, nonceDataAvailabilityMode: DAMode, ): Felt { diff --git a/lib/src/main/kotlin/com/swmansion/starknet/data/serializers/JsonRpcErrorPolymorphicSerializer.kt b/lib/src/main/kotlin/com/swmansion/starknet/data/serializers/JsonRpcErrorSerializer.kt similarity index 52% rename from lib/src/main/kotlin/com/swmansion/starknet/data/serializers/JsonRpcErrorPolymorphicSerializer.kt rename to lib/src/main/kotlin/com/swmansion/starknet/data/serializers/JsonRpcErrorSerializer.kt index 94c2d1219..33175f653 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/data/serializers/JsonRpcErrorPolymorphicSerializer.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/data/serializers/JsonRpcErrorSerializer.kt @@ -1,9 +1,6 @@ package com.swmansion.starknet.data.serializers -import com.swmansion.starknet.provider.rpc.JsonRpcContractError import com.swmansion.starknet.provider.rpc.JsonRpcError -import com.swmansion.starknet.provider.rpc.JsonRpcStandardError -import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.KSerializer import kotlinx.serialization.SerializationException import kotlinx.serialization.descriptors.PrimitiveKind @@ -13,23 +10,8 @@ import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.json.* -internal object JsonRpcErrorPolymorphicSerializer : JsonContentPolymorphicSerializer(JsonRpcError::class) { - override fun selectDeserializer(element: JsonElement): DeserializationStrategy { - val jsonElement = element.jsonObject - - val isContractError = "data" in jsonElement && - jsonElement["data"]!! is JsonObject && - "revert_error" in jsonElement["data"]!!.jsonObject && - jsonElement["data"]!!.jsonObject.size == 1 - return when { - isContractError -> JsonRpcContractError.serializer() - else -> JsonRpcStandardError.serializer() - } - } -} - -internal object JsonRpcStandardErrorSerializer : KSerializer { - override fun deserialize(decoder: Decoder): JsonRpcStandardError { +internal object JsonRpcErrorSerializer : KSerializer { + override fun deserialize(decoder: Decoder): JsonRpcError { val input = decoder as? JsonDecoder ?: throw SerializationException("Expected JsonInput for ${decoder::class}") val jsonObject = input.decodeJsonElement().jsonObject @@ -44,7 +26,7 @@ internal object JsonRpcStandardErrorSerializer : KSerializer, - accountDeploymentData: List, - nonceDataAvailabilityMode: DAMode, - feeDataAvailabilityMode: DAMode, ): InvokeTransactionV3 { val hash = TransactionHashCalculator.calculateInvokeTxV3Hash( senderAddress = senderAddress, @@ -690,6 +670,7 @@ object TransactionFactory { } @JvmStatic + @JvmOverloads fun makeDeployAccountV1Transaction( classHash: Felt, contractAddress: Felt, @@ -697,7 +678,7 @@ object TransactionFactory { calldata: Calldata, chainId: StarknetChainId, version: Felt, - maxFee: Felt = Felt.ZERO, + maxFee: Felt, signature: Signature = emptyList(), nonce: Felt = Felt.ZERO, ): DeployAccountTransactionV1 { @@ -724,6 +705,7 @@ object TransactionFactory { } @JvmStatic + @JvmOverloads fun makeDeployAccountV3Transaction( classHash: Felt, senderAddress: Felt, @@ -734,10 +716,6 @@ object TransactionFactory { signature: Signature = emptyList(), nonce: Felt = Felt.ZERO, resourceBounds: ResourceBoundsMapping, - tip: Uint64, - paymasterData: List, - nonceDataAvailabilityMode: DAMode, - feeDataAvailabilityMode: DAMode, ): DeployAccountTransactionV3 { val hash = TransactionHashCalculator.calculateDeployAccountV3TxHash( classHash = classHash, @@ -770,6 +748,7 @@ object TransactionFactory { } @JvmStatic + @JvmOverloads fun makeDeclareV1Transaction( classHash: Felt, senderAddress: Felt, @@ -801,6 +780,7 @@ object TransactionFactory { } @JvmStatic + @JvmOverloads fun makeDeclareV2Transaction( senderAddress: Felt, contractDefinition: Cairo1ContractDefinition, @@ -836,6 +816,7 @@ object TransactionFactory { } @JvmStatic + @JvmOverloads fun makeDeclareV3Transaction( senderAddress: Felt, contractDefinition: Cairo1ContractDefinition, @@ -843,13 +824,8 @@ object TransactionFactory { version: Felt, nonce: Felt, casmContractDefinition: CasmContractDefinition, - resourceBounds: ResourceBoundsMapping, - tip: Uint64, - paymasterData: List, - accountDeploymentData: List, - nonceDataAvailabilityMode: DAMode, - feeDataAvailabilityMode: DAMode, signature: Signature = emptyList(), + resourceBounds: ResourceBoundsMapping, ): DeclareTransactionV3 { val classHash = Cairo1ClassHashCalculator.computeSierraClassHash(contractDefinition) val compiledClassHash = Cairo1ClassHashCalculator.computeCasmClassHash(casmContractDefinition) diff --git a/lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/TransactionPayload.kt b/lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/TransactionPayload.kt index 63a176438..b4dad2e90 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/TransactionPayload.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/data/types/transactions/TransactionPayload.kt @@ -35,20 +35,11 @@ data class InvokeTransactionV1Payload( @SerialName("nonce") val nonce: Felt, -) : InvokeTransactionPayload() { - - constructor(senderAddress: Felt, calldata: Calldata, signature: Signature, maxFee: Felt, nonce: Felt) : this( - senderAddress = senderAddress, - calldata = calldata, - signature = signature, - maxFee = maxFee, - version = Felt.ONE, - nonce = nonce, - ) -} +) : InvokeTransactionPayload() +@Suppress("DataClassPrivateConstructor") @Serializable -data class InvokeTransactionV3Payload( +data class InvokeTransactionV3Payload private constructor( @SerialName("sender_address") val senderAddress: Felt, @@ -82,30 +73,25 @@ data class InvokeTransactionV3Payload( @SerialName("version") val version: Felt, ) : InvokeTransactionPayload() { - constructor( senderAddress: Felt, calldata: Calldata, signature: Signature, nonce: Felt, resourceBounds: ResourceBoundsMapping, - tip: Uint64, - paymasterData: List, - accountDeploymentData: List, - nonceDataAvailabilityMode: DAMode, - feeDataAvailabilityMode: DAMode, + version: Felt, ) : this( senderAddress = senderAddress, calldata = calldata, signature = signature, nonce = nonce, resourceBounds = resourceBounds, - tip = tip, - paymasterData = paymasterData, - accountDeploymentData = accountDeploymentData, - nonceDataAvailabilityMode = nonceDataAvailabilityMode, - feeDataAvailabilityMode = feeDataAvailabilityMode, - version = Felt(3), + tip = Uint64.ZERO, + paymasterData = emptyList(), + accountDeploymentData = emptyList(), + nonceDataAvailabilityMode = DAMode.L1, + feeDataAvailabilityMode = DAMode.L1, + version = version, ) } @@ -130,7 +116,7 @@ data class DeclareTransactionV1Payload( val senderAddress: Felt, @SerialName("version") - val version: Felt = Felt.ONE, + val version: Felt, @SerialName("type") override val type: TransactionType = TransactionType.DECLARE, @@ -157,14 +143,15 @@ data class DeclareTransactionV2Payload( val compiledClassHash: Felt, @SerialName("version") - val version: Felt = Felt(2), + val version: Felt, @SerialName("type") override val type: TransactionType = TransactionType.DECLARE, ) : DeclareTransactionPayload() +@Suppress("DataClassPrivateConstructor") @Serializable -data class DeclareTransactionV3Payload( +data class DeclareTransactionV3Payload private constructor( @SerialName("contract_class") val contractDefinition: Cairo1ContractDefinition, @@ -199,11 +186,34 @@ data class DeclareTransactionV3Payload( val feeDataAvailabilityMode: DAMode, @SerialName("version") - val version: Felt = Felt(3), + val version: Felt, @SerialName("type") override val type: TransactionType = TransactionType.DECLARE, -) : DeclareTransactionPayload() +) : DeclareTransactionPayload() { + constructor( + contractDefinition: Cairo1ContractDefinition, + nonce: Felt, + signature: Signature, + senderAddress: Felt, + compiledClassHash: Felt, + resourceBounds: ResourceBoundsMapping, + version: Felt, + ) : this( + contractDefinition = contractDefinition, + nonce = nonce, + signature = signature, + senderAddress = senderAddress, + compiledClassHash = compiledClassHash, + resourceBounds = resourceBounds, + tip = Uint64.ZERO, + paymasterData = emptyList(), + accountDeploymentData = emptyList(), + nonceDataAvailabilityMode = DAMode.L1, + feeDataAvailabilityMode = DAMode.L1, + version = version, + ) +} @Serializable sealed class DeployAccountTransactionPayload() : TransactionPayload() @@ -235,8 +245,9 @@ data class DeployAccountTransactionV1Payload( override val type: TransactionType = TransactionType.DEPLOY_ACCOUNT, ) : DeployAccountTransactionPayload() +@Suppress("DataClassPrivateConstructor") @Serializable -data class DeployAccountTransactionV3Payload( +data class DeployAccountTransactionV3Payload private constructor( @SerialName("class_hash") val classHash: Felt, @@ -272,4 +283,26 @@ data class DeployAccountTransactionV3Payload( @SerialName("type") override val type: TransactionType = TransactionType.DEPLOY_ACCOUNT, -) : DeployAccountTransactionPayload() +) : DeployAccountTransactionPayload() { + constructor( + classHash: Felt, + salt: Felt, + constructorCalldata: Calldata, + version: Felt, + nonce: Felt, + signature: Signature, + resourceBounds: ResourceBoundsMapping, + ) : this( + classHash = classHash, + salt = salt, + constructorCalldata = constructorCalldata, + version = version, + nonce = nonce, + signature = signature, + resourceBounds = resourceBounds, + tip = Uint64.ZERO, + paymasterData = emptyList(), + nonceDataAvailabilityMode = DAMode.L1, + feeDataAvailabilityMode = DAMode.L1, + ) +} diff --git a/lib/src/main/kotlin/com/swmansion/starknet/deployercontract/Deployer.kt b/lib/src/main/kotlin/com/swmansion/starknet/deployercontract/Deployer.kt index 0849f66a4..aa2dc944a 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/deployercontract/Deployer.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/deployercontract/Deployer.kt @@ -2,6 +2,7 @@ package com.swmansion.starknet.deployercontract import com.swmansion.starknet.data.types.Calldata import com.swmansion.starknet.data.types.Felt +import com.swmansion.starknet.data.types.ResourceBounds import com.swmansion.starknet.provider.Request import com.swmansion.starknet.provider.exceptions.RequestFailedException @@ -20,7 +21,7 @@ class SaltGenerationFailedException : RuntimeException() */ interface Deployer { /** - * Deploy a contract through Universal Deployer Contract (UDC) + * Deploy a contract through Universal Deployer Contract (UDC) using version 1 invoke transaction * * @param classHash a class hash of the declared contract * @param unique set whether deployed contract address should be based on account address or not @@ -30,7 +31,7 @@ interface Deployer { * * @throws RequestFailedException */ - fun deployContract( + fun deployContractV1( classHash: Felt, unique: Boolean, salt: Felt, @@ -39,25 +40,61 @@ interface Deployer { ): Request /** - * Deploy a contract through Universal Deployer Contract (UDC) + * Deploy a contract through Universal Deployer Contract (UDC) using version 3 invoke transaction * * @param classHash a class hash of the declared contract * @param unique set whether deployed contract address should be based on account address or not * @param salt a salt to be used to calculate deployed contract address * @param constructorCalldata constructor calldata + * @param l1ResourceBounds L1 resource bounds for the transaction * * @throws RequestFailedException */ - fun deployContract( + fun deployContractV3( classHash: Felt, unique: Boolean, salt: Felt, constructorCalldata: Calldata, + l1ResourceBounds: ResourceBounds, ): Request /** - * Deploy a contract through Universal Deployer Contract (UDC) with random generated salt and - * unique parameter set to true + * Deploy a contract through Universal Deployer Contract (UDC) using version 1 invoke transaction + * + * @param classHash a class hash of the declared contract + * @param unique set whether deployed contract address should be based on account address or not + * @param salt a salt to be used to calculate deployed contract address + * @param constructorCalldata constructor calldata + * + * @throws RequestFailedException + */ + fun deployContractV1( + classHash: Felt, + unique: Boolean, + salt: Felt, + constructorCalldata: Calldata, + ): Request + + /** + * Deploy a contract through Universal Deployer Contract (UDC) using version 3 invoke transaction + * + * @param classHash a class hash of the declared contract + * @param unique set whether deployed contract address should be based on account address or not + * @param salt a salt to be used to calculate deployed contract address + * @param constructorCalldata constructor calldata + * + * @throws RequestFailedException + */ + fun deployContractV3( + classHash: Felt, + unique: Boolean, + salt: Felt, + constructorCalldata: Calldata, + ): Request + + /** + * Deploy a contract through Universal Deployer Contract (UDC) using version 1 invoke transaction + * with random generated salt and unique parameter set to true * * @param classHash a class hash of the declared contract * @param constructorCalldata constructor calldata @@ -66,18 +103,42 @@ interface Deployer { * @throws RequestFailedException * @throws SaltGenerationFailedException */ - fun deployContract(classHash: Felt, constructorCalldata: Calldata, maxFee: Felt): Request + fun deployContractV1(classHash: Felt, constructorCalldata: Calldata, maxFee: Felt): Request + + /** + * Deploy a contract through Universal Deployer Contract (UDC) using version 3 invoke transaction + * with random generated salt and unique parameter set to true + * + * @param classHash a class hash of the declared contract + * @param constructorCalldata constructor calldata + * @param l1ResourceBounds L1 resource bounds for the transaction + * + * @throws RequestFailedException + * @throws SaltGenerationFailedException + */ + fun deployContractV3(classHash: Felt, constructorCalldata: Calldata, l1ResourceBounds: ResourceBounds): Request + + /** + * Deploy a contract through Universal Deployer Contract (UDC) using version 1 invoke transaction + * with random generated salt and unique parameter set to true + * + * @param classHash a class hash of the declared contract + * @param constructorCalldata constructor calldata + * @throws RequestFailedException + * @throws SaltGenerationFailedException + */ + fun deployContractV1(classHash: Felt, constructorCalldata: Calldata): Request /** - * Deploy a contract through Universal Deployer Contract (UDC) with random generated salt and - * unique parameter set to true + * Deploy a contract through Universal Deployer Contract (UDC) using version 3 invoke transaction + * with random generated salt and unique parameter set to true * * @param classHash a class hash of the declared contract * @param constructorCalldata constructor calldata * @throws RequestFailedException * @throws SaltGenerationFailedException */ - fun deployContract(classHash: Felt, constructorCalldata: Calldata): Request + fun deployContractV3(classHash: Felt, constructorCalldata: Calldata): Request /** * Get a contract address from the deployment 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 f7b87a4e6..e6b28ebfb 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/deployercontract/StandardDeployer.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/deployercontract/StandardDeployer.kt @@ -2,10 +2,7 @@ package com.swmansion.starknet.deployercontract import com.swmansion.starknet.account.Account import com.swmansion.starknet.data.selectorFromName -import com.swmansion.starknet.data.types.Call -import com.swmansion.starknet.data.types.Calldata -import com.swmansion.starknet.data.types.Event -import com.swmansion.starknet.data.types.Felt +import com.swmansion.starknet.data.types.* import com.swmansion.starknet.data.types.transactions.* import com.swmansion.starknet.extensions.map import com.swmansion.starknet.extensions.toFelt @@ -18,7 +15,7 @@ class StandardDeployer( private val provider: Provider, private val account: Account, ) : Deployer { - override fun deployContract( + override fun deployContractV1( classHash: Felt, unique: Boolean, salt: Felt, @@ -27,28 +24,61 @@ class StandardDeployer( ): Request { val call = buildDeployContractCall(classHash, unique, salt, constructorCalldata) - return account.execute(call, maxFee).map { ContractDeployment(it.transactionHash) } + return account.executeV1(call, maxFee).map { ContractDeployment(it.transactionHash) } } - override fun deployContract( + override fun deployContractV3( classHash: Felt, unique: Boolean, salt: Felt, constructorCalldata: Calldata, + l1ResourceBounds: ResourceBounds, ): Request { val call = buildDeployContractCall(classHash, unique, salt, constructorCalldata) - return account.execute(call).map { ContractDeployment(it.transactionHash) } + return account.executeV3(call, l1ResourceBounds).map { ContractDeployment(it.transactionHash) } } - override fun deployContract(classHash: Felt, constructorCalldata: Calldata, maxFee: Felt): Request { + override fun deployContractV1( + classHash: Felt, + unique: Boolean, + salt: Felt, + constructorCalldata: Calldata, + ): Request { + val call = buildDeployContractCall(classHash, unique, salt, constructorCalldata) + + return account.executeV1(call).map { ContractDeployment(it.transactionHash) } + } + + override fun deployContractV3( + classHash: Felt, + unique: Boolean, + salt: Felt, + constructorCalldata: Calldata, + ): Request { + val call = buildDeployContractCall(classHash, unique, salt, constructorCalldata) + + return account.executeV3(call).map { ContractDeployment(it.transactionHash) } + } + + override fun deployContractV1(classHash: Felt, constructorCalldata: Calldata, maxFee: Felt): Request { + val salt = randomSalt() + return deployContractV1(classHash, true, salt, constructorCalldata, maxFee) + } + + override fun deployContractV3(classHash: Felt, constructorCalldata: Calldata, l1ResourceBounds: ResourceBounds): Request { + val salt = randomSalt() + return deployContractV3(classHash, true, salt, constructorCalldata, l1ResourceBounds) + } + + override fun deployContractV1(classHash: Felt, constructorCalldata: Calldata): Request { val salt = randomSalt() - return deployContract(classHash, true, salt, constructorCalldata, maxFee) + return deployContractV1(classHash, true, salt, constructorCalldata) } - override fun deployContract(classHash: Felt, constructorCalldata: Calldata): Request { + override fun deployContractV3(classHash: Felt, constructorCalldata: Calldata): Request { val salt = randomSalt() - return deployContract(classHash, true, salt, constructorCalldata) + return deployContractV3(classHash, true, salt, constructorCalldata) } private fun buildDeployContractCall( 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 f0ab22625..c4bb044dd 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/provider/Provider.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/provider/Provider.kt @@ -422,7 +422,7 @@ interface Provider { * * Estimate a fee for a provided transaction list. * - * @param payload transaction, for which the fee is to be estimated. + * @param payload transactions, for which the fee is to be estimated. * @param blockHash a hash of the block in respect to what the query will be made * @param simulationFlags set of flags to be used for simulation. * @@ -439,22 +439,19 @@ interface Provider { * * Estimate a fee for a provided transaction list. * - * @param payload transaction, for which the fee is to be estimated. + * @param payload transactions, for which the fee is to be estimated. * @param blockHash a hash of the block in respect to what the query will be made * * @throws RequestFailedException */ - fun getEstimateFee( - payload: List, - blockHash: Felt, - ): Request> + fun getEstimateFee(payload: List, blockHash: Felt): Request> /** * Estimate a fee. * * Estimate a fee for a provided transaction list. * - * @param payload transaction, for which the fee is to be estimated. + * @param payload transactions, for which the fee is to be estimated. * @param simulationFlags set of flags to be used for simulation. * @param blockNumber a number of the block in respect to what the query will be made * @@ -471,22 +468,19 @@ interface Provider { * * Estimate a fee for a provided transaction list. * - * @param payload transaction, for which the fee is to be estimated. + * @param payload transactions, for which the fee is to be estimated. * @param blockNumber a number of the block in respect to what the query will be made * * @throws RequestFailedException */ - fun getEstimateFee( - payload: List, - blockNumber: Int, - ): Request> + fun getEstimateFee(payload: List, blockNumber: Int): Request> /** * Estimate a fee. * * Estimate a fee for a provided transaction list. * - * @param payload transaction, for which the fee is to be estimated. + * @param payload transactions, for which the fee is to be estimated. * @param simulationFlags set of flags to be used for simulation. * @param blockTag a tag of the block in respect to what the query will be made * @@ -503,22 +497,19 @@ interface Provider { * * Estimate a fee for a provided transaction list. * - * @param payload transaction, for which the fee is to be estimated. + * @param payload transactions, for which the fee is to be estimated. * @param blockTag a tag of the block in respect to what the query will be made * * @throws RequestFailedException */ - fun getEstimateFee( - payload: List, - blockTag: BlockTag, - ): Request> + fun getEstimateFee(payload: List, blockTag: BlockTag): Request> /** * Estimate a fee. * * Estimate a fee for a provided transaction list for pending block. * - * @param payload transaction, for which the fee is to be estimated. + * @param payload transactions, for which the fee is to be estimated. * @param simulationFlags set of flags to be used for simulation * * @throws RequestFailedException diff --git a/lib/src/main/kotlin/com/swmansion/starknet/provider/rpc/BuildJsonHttpDeserializer.kt b/lib/src/main/kotlin/com/swmansion/starknet/provider/rpc/BuildJsonHttpDeserializer.kt index 5f308867e..f7db5c00c 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/provider/rpc/BuildJsonHttpDeserializer.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/provider/rpc/BuildJsonHttpDeserializer.kt @@ -1,7 +1,6 @@ package com.swmansion.starknet.provider.rpc -import com.swmansion.starknet.data.serializers.JsonRpcErrorPolymorphicSerializer -import com.swmansion.starknet.data.serializers.JsonRpcStandardErrorSerializer +import com.swmansion.starknet.data.serializers.JsonRpcErrorSerializer import com.swmansion.starknet.provider.exceptions.RequestFailedException import com.swmansion.starknet.provider.exceptions.RpcRequestFailedException import com.swmansion.starknet.service.http.HttpResponseDeserializer @@ -21,54 +20,20 @@ private data class JsonRpcResponse( val result: T? = null, @SerialName("error") - @Serializable(with = JsonRpcErrorPolymorphicSerializer::class) val error: JsonRpcError? = null, ) -internal sealed class JsonRpcError { +@Serializable(with = JsonRpcErrorSerializer::class) +internal data class JsonRpcError( @SerialName("code") - abstract val code: Int + val code: Int, @SerialName("message") - abstract val message: String + val message: String, @SerialName("data") - abstract val data: Any? -} - -@Serializable(with = JsonRpcStandardErrorSerializer::class) -internal data class JsonRpcStandardError( - @SerialName("code") - override val code: Int, - - @SerialName("message") - override val message: String, - - @SerialName("data") - override val data: String? = null, -) : JsonRpcError() - -@Serializable -internal data class JsonRpcContractError( - @SerialName("code") - override val code: Int, - - @SerialName("message") - override val message: String, - - @SerialName("data") - override val data: JsonRpcContractErrorData, -) : JsonRpcError() - -@Serializable -internal data class JsonRpcContractErrorData( - @SerialName("revert_error") - val revertError: String, -) { - override fun toString(): String { - return revertError - } -} + val data: String? = null, +) @JvmSynthetic internal fun buildJsonHttpDeserializer( @@ -91,7 +56,7 @@ internal fun buildJsonHttpDeserializer( throw RpcRequestFailedException( code = jsonRpcResponse.error.code, message = jsonRpcResponse.error.message, - data = jsonRpcResponse.error.data?.toString(), + data = jsonRpcResponse.error.data, payload = response.body, ) } 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 c2c0a7de9..9c7985a76 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 @@ -40,7 +40,7 @@ class JsonRpcProvider( private val jsonWithIgnoreUnknownKeys by lazy { Json { ignoreUnknownKeys = true } } private val defaultFeeEstimateSimulationFlags: Set by lazy { - setOf(SimulationFlagForEstimateFee.SKIP_VALIDATE) + emptySet() } } diff --git a/lib/src/test/kotlin/com/swmansion/starknet/data/TransactionHashCalculatorTest.kt b/lib/src/test/kotlin/com/swmansion/starknet/data/TransactionHashCalculatorTest.kt index 78d4dac18..6aa11e20b 100644 --- a/lib/src/test/kotlin/com/swmansion/starknet/data/TransactionHashCalculatorTest.kt +++ b/lib/src/test/kotlin/com/swmansion/starknet/data/TransactionHashCalculatorTest.kt @@ -1,44 +1,198 @@ package com.swmansion.starknet.data -import com.swmansion.starknet.data.types.Felt -import com.swmansion.starknet.data.types.StarknetChainId +import com.swmansion.starknet.data.types.* +import com.swmansion.starknet.data.types.transactions.DAMode import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test internal class TransactionHashCalculatorTest { - private val calldata = listOf(Felt(999), Felt(888), Felt(777)) - private val maxFee = Felt.fromHex("0xabcd987654210") - private val chainId = StarknetChainId.GOERLI - private val version = Felt.ONE - - @Test - fun calculateInvokeTxHash() { - val hash = TransactionHashCalculator.calculateInvokeTxV1Hash( - contractAddress = Felt.fromHex("0x6352037a8acbb31095a8ed0f4aa8d8639e13b705b043a1b08f9640d2f9f0d56"), - calldata = calldata, - chainId = chainId, - version = version, - nonce = Felt(9876), - maxFee = maxFee, - ) - val expected = Felt.fromHex("0x119b1a69e0c35b9035be945d3a1d551f2f78473b10311734fafb1f5df3f61d9") - - assertEquals(expected, hash) + @Nested + inner class DeprecatedTransactionHashTest { + private val calldata = listOf(Felt(999), Felt(888), Felt(777)) + private val maxFee = Felt.fromHex("0xabcd987654210") + private val chainId = StarknetChainId.GOERLI + + @Test + fun `calculate invoke v1 transaction hash`() { + val hash = TransactionHashCalculator.calculateInvokeTxV1Hash( + contractAddress = Felt.fromHex("0x6352037a8acbb31095a8ed0f4aa8d8639e13b705b043a1b08f9640d2f9f0d56"), + calldata = calldata, + chainId = chainId, + version = Felt.ONE, + nonce = Felt(9876), + maxFee = maxFee, + ) + val expected = Felt.fromHex("0x119b1a69e0c35b9035be945d3a1d551f2f78473b10311734fafb1f5df3f61d9") + assertEquals(expected, hash) + } + + @Test + fun `calculate deploy account v1 transaction hash`() { + val hash = TransactionHashCalculator.calculateDeployAccountV1TxHash( + classHash = Felt.fromHex("0x21a7f43387573b68666669a0ed764252ce5367708e696e31967764a90b429c2"), + calldata = calldata, + salt = Felt(1234), + chainId = chainId, + version = Felt.ONE, + maxFee = maxFee, + nonce = Felt.ZERO, + ) + val expected = Felt.fromHex("0x68beaf15e356928a1850cf343be85032efad964324b0abca4a9a57ff2057ef7") + assertEquals(expected, hash) + } + + @Test + fun `calculate declare v1 transaction hash`() { + val hash = TransactionHashCalculator.calculateDeclareV1TxHash( + classHash = Felt.fromHex("0x5ae9d09292a50ed48c5930904c880dab56e85b825022a7d689cfc9e65e01ee7"), + senderAddress = Felt.fromHex("0x6352037a8acbb31095a8ed0f4aa8d8639e13b705b043a1b08f9640d2f9f0d56"), + version = Felt.ONE, + chainId = chainId, + nonce = Felt(9876), + maxFee = maxFee, + ) + val expected = Felt.fromHex("0x64584f4e821e8d3bcd08295cbd7675858ca9a5a882108e9a31df273e2fb320f") + assertEquals(expected, hash) + } + + @Test + fun `calculate declare v2 transaction hash`() { + val hash = TransactionHashCalculator.calculateDeclareV2TxHash( + classHash = Felt.fromHex("0x5ae9d09292a50ed48c5930904c880dab56e85b825022a7d689cfc9e65e01ee7"), + compiledClassHash = Felt.fromHex("0x1add56d64bebf8140f3b8a38bdf102b7874437f0c861ab4ca7526ec33b4d0f8"), + senderAddress = Felt.fromHex("0x6352037a8acbb31095a8ed0f4aa8d8639e13b705b043a1b08f9640d2f9f0d56"), + version = Felt(2), + chainId = chainId, + nonce = Felt(9876), + maxFee = maxFee, + ) + val expected = Felt.fromHex("0x31e70aad6b93265e2bd1f619841115320a2a2899759a3af3b1d9582f23e7588") + assertEquals(expected, hash) + } } - @Test - fun calculateDeployAccountTxHash() { - val hash = TransactionHashCalculator.calculateDeployAccountV1TxHash( - classHash = Felt.fromHex("0x21a7f43387573b68666669a0ed764252ce5367708e696e31967764a90b429c2"), - calldata = calldata, - salt = Felt(1234), - chainId = chainId, - version = version, - maxFee = maxFee, - nonce = Felt.ZERO, - ) - val expected = Felt.fromHex("0x68beaf15e356928a1850cf343be85032efad964324b0abca4a9a57ff2057ef7") - - assertEquals(expected, hash) + @Nested + inner class TransactionHashV3Test { + private val chainId = StarknetChainId.GOERLI + + @Test + fun `prepare data availability modes`() { + val result = TransactionHashCalculator.prepareDataAvailabilityModes( + feeDataAvailabilityMode = DAMode.L1, + nonceDataAvailabilityMode = DAMode.L1, + ) + assertEquals(Felt.ZERO, result) + + val result2 = TransactionHashCalculator.prepareDataAvailabilityModes( + feeDataAvailabilityMode = DAMode.L2, + nonceDataAvailabilityMode = DAMode.L1, + ) + assertEquals(Felt.ONE, result2) + + val result3 = TransactionHashCalculator.prepareDataAvailabilityModes( + feeDataAvailabilityMode = DAMode.L1, + nonceDataAvailabilityMode = DAMode.L2, + ) + assertEquals(Felt.fromHex("0x100000000"), result3) + + val result4 = TransactionHashCalculator.prepareDataAvailabilityModes( + feeDataAvailabilityMode = DAMode.L2, + nonceDataAvailabilityMode = DAMode.L2, + ) + assertEquals(Felt.fromHex("0x100000001"), result4) + } + + @Test + fun `calculate invoke v3 transaction hash`() { + val hash = TransactionHashCalculator.calculateInvokeTxV3Hash( + senderAddress = Felt.fromHex("0x3f6f3bc663aedc5285d6013cc3ffcbc4341d86ab488b8b68d297f8258793c41"), + calldata = listOf( + Felt.fromHex("0x2"), + Felt.fromHex("0x4c312760dfd17a954cdd09e76aa9f149f806d88ec3e402ffaf5c4926f568a42"), + Felt.fromHex("0x31aafc75f498fdfa7528880ad27246b4c15af4954f96228c9a132b328de1c92"), + Felt.fromHex("0x0"), + Felt.fromHex("0x6"), + Felt.fromHex("0x450703c32370cf7ffff540b9352e7ee4ad583af143a361155f2b485c0c39684"), + Felt.fromHex("0xb17d8a2731ba7ca1816631e6be14f0fc1b8390422d649fa27f0fbb0c91eea8"), + Felt.fromHex("0x6"), + Felt.fromHex("0x0"), + Felt.fromHex("0x6"), + Felt.fromHex("0x6333f10b24ed58cc33e9bac40b0d52e067e32a175a97ca9e2ce89fe2b002d82"), + Felt.fromHex("0x3"), + Felt.fromHex("0x602e89fe5703e5b093d13d0a81c9e6d213338dc15c59f4d3ff3542d1d7dfb7d"), + Felt.fromHex("0x20d621301bea11ffd9108af1d65847e9049412159294d0883585d4ad43ad61b"), + Felt.fromHex("0x276faadb842bfcbba834f3af948386a2eb694f7006e118ad6c80305791d3247"), + Felt.fromHex("0x613816405e6334ab420e53d4b38a0451cb2ebca2755171315958c87d303cf6"), + ), + chainId = chainId, + version = Felt(3), + nonce = Felt.fromHex("0x8a9"), + accountDeploymentData = emptyList(), + tip = Uint64.ZERO, + resourceBounds = ResourceBoundsMapping( + l1Gas = ResourceBounds( + maxAmount = Uint64.fromHex("0x186a0"), + maxPricePerUnit = Uint128.fromHex("0x5af3107a4000"), + ), + ), + paymasterData = emptyList(), + feeDataAvailabilityMode = DAMode.L1, + nonceDataAvailabilityMode = DAMode.L1, + ) + val expected = Felt.fromHex("0x41906f1c314cca5f43170ea75d3b1904196a10101190d2b12a41cc61cfd17c") + assertEquals(expected, hash) + } + + @Test + fun `caculate deploy account v3 transaction hash`() { + val hash = TransactionHashCalculator.calculateDeployAccountV3TxHash( + constructorCalldata = listOf( + Felt.fromHex("0x5cd65f3d7daea6c63939d659b8473ea0c5cd81576035a4d34e52fb06840196c"), + ), + classHash = Felt.fromHex("0x2338634f11772ea342365abd5be9d9dc8a6f44f159ad782fdebd3db5d969738"), + salt = Felt.ZERO, + chainId = chainId, + version = Felt(3), + nonce = Felt.ZERO, + resourceBounds = ResourceBoundsMapping( + l1Gas = ResourceBounds( + maxAmount = Uint64.fromHex("0x186a0"), + maxPricePerUnit = Uint128.fromHex("0x5af3107a4000"), + ), + ), + tip = Uint64.ZERO, + paymasterData = emptyList(), + feeDataAvailabilityMode = DAMode.L1, + nonceDataAvailabilityMode = DAMode.L1, + ) + val expected = Felt.fromHex("0x29fd7881f14380842414cdfdd8d6c0b1f2174f8916edcfeb1ede1eb26ac3ef0") + assertEquals(expected, hash) + } + + @Test + fun `calculate declare v3 transaction hash`() { + val hash = TransactionHashCalculator.calculateDeclareV3TxHash( + classHash = Felt.fromHex("0x5ae9d09292a50ed48c5930904c880dab56e85b825022a7d689cfc9e65e01ee7"), + compiledClassHash = Felt.fromHex("0x1add56d64bebf8140f3b8a38bdf102b7874437f0c861ab4ca7526ec33b4d0f8"), + senderAddress = Felt.fromHex("0x2fab82e4aef1d8664874e1f194951856d48463c3e6bf9a8c68e234a629a6f50"), + version = Felt(3), + chainId = chainId, + nonce = Felt.ONE, + resourceBounds = ResourceBoundsMapping( + l1Gas = ResourceBounds( + maxAmount = Uint64.fromHex("0x186a0"), + maxPricePerUnit = Uint128.fromHex("0x2540be400"), + ), + ), + tip = Uint64.ZERO, + paymasterData = emptyList(), + accountDeploymentData = emptyList(), + feeDataAvailabilityMode = DAMode.L1, + nonceDataAvailabilityMode = DAMode.L1, + ) + val expected = Felt.fromHex("0x41d1f5206ef58a443e7d3d1ca073171ec25fa75313394318fc83a074a6631c3") + assertEquals(expected, hash) + } } } diff --git a/lib/src/test/kotlin/com/swmansion/starknet/data/types/FeltTest.kt b/lib/src/test/kotlin/com/swmansion/starknet/data/types/FeltTest.kt deleted file mode 100644 index ca15e1b4d..000000000 --- a/lib/src/test/kotlin/com/swmansion/starknet/data/types/FeltTest.kt +++ /dev/null @@ -1,98 +0,0 @@ -package com.swmansion.starknet.data.types - -import com.swmansion.starknet.data.types.conversions.ConvertibleToCalldata -import com.swmansion.starknet.extensions.toCalldata -import com.swmansion.starknet.extensions.toFelt -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.assertThrows -import java.math.BigInteger - -internal class FeltTest { - @Test - fun `Felt can't be created with a negative value`() { - assertThrows("Default Felt constructor does not accept negative numbers, [-1] given.") { - Felt(BigInteger.valueOf(-1)) - } - } - - @Test - fun `Felt can't be created with a value bigger than PRIME`() { - assertThrows( - "Default Felt constructor accepts values smaller than Felt.PRIME, [3618502788666131213697322783095070105623107215331596699973092056135872020481] given.", - ) { - Felt(Felt.PRIME) - } - } - - @Test - fun feltToString() { - assertEquals( - "Felt(0xabcdef01234567890)", - Felt.fromHex("0xabcdef01234567890").toString(), - ) - } - - @Test - fun `fromShortString short string`() { - val encoded = Felt.fromShortString("hello") - - assertEquals(Felt.fromHex("0x68656c6c6f"), encoded) - } - - @Test - fun `fromShortString too long string should fail`() { - assertThrows("Short string cannot be longer than 31 characters") { - Felt.fromShortString("a".repeat(32)) - } - } - - @Test - fun `fromShortString non ascii string should fail`() { - assertThrows("String to be encoded must be an ascii string") { - Felt.fromShortString("hello\uD83D\uDE00") - } - } - - @Test - fun `toShortString short string`() { - val decoded = Felt.fromHex("0x68656c6c6f").toShortString() - - assertEquals("hello", decoded) - } - - @Test - fun `toShortString short string - start pad with 0`() { - val decoded = Felt.fromHex("0xa68656c6c6f").toShortString() - - assertEquals("\nhello", decoded) - } - - @Test - fun `felt array is convertible to calldata`() { - val convertibleToCalldata = ArrayList() - - val feltArray1 = FeltArray(Felt(100), Felt(200)) - val feltArray2 = FeltArray(listOf(Felt(300), Felt(400))) - feltArray2.add(Felt(500)) - val emptyFeltArray = FeltArray() - - convertibleToCalldata.add(Felt(15)) - convertibleToCalldata.add(feltArray1.size.toFelt) - convertibleToCalldata.add(feltArray1) - convertibleToCalldata.add(feltArray2.size.toFelt) - convertibleToCalldata.add(feltArray2) - convertibleToCalldata.add(emptyFeltArray.size.toFelt) - convertibleToCalldata.add(emptyFeltArray) - - val calldata = convertibleToCalldata.toCalldata() - - val expectedCalldata = listOf( - Felt(15), - Felt(2), Felt(100), Felt(200), - Felt(3), Felt(300), Felt(400), Felt(500), - Felt(0), - ) - assertEquals(expectedCalldata, calldata) - } -} diff --git a/lib/src/test/kotlin/com/swmansion/starknet/data/types/NumAsHexBaseTests.kt b/lib/src/test/kotlin/com/swmansion/starknet/data/types/NumAsHexBaseTests.kt new file mode 100644 index 000000000..a4c57e935 --- /dev/null +++ b/lib/src/test/kotlin/com/swmansion/starknet/data/types/NumAsHexBaseTests.kt @@ -0,0 +1,187 @@ +package com.swmansion.starknet.data.types + +import com.swmansion.starknet.data.types.conversions.ConvertibleToCalldata +import com.swmansion.starknet.extensions.toCalldata +import com.swmansion.starknet.extensions.toFelt +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import java.math.BigInteger + +internal class NumAsHexBaseTests { + @Test + fun `numbers can't be created with a negative value`() { + assertThrows { + Felt(BigInteger.valueOf(-1)) + } + assertThrows { + Uint64(BigInteger.valueOf(-1)) + } + assertThrows { + Uint128(BigInteger.valueOf(-1)) + } + assertThrows { + Uint128(BigInteger.valueOf(-1)) + } + assertThrows { + NumAsHex(BigInteger.valueOf(-1)) + } + assertThrows { + Uint256(BigInteger.valueOf(-1)) + } + } + + @Test + fun `numbers overflow`() { + assertThrows { + Felt(Felt.PRIME) + } + assertThrows { + Uint64(Uint64.MAX + BigInteger.ONE) + } + assertThrows { + Uint128(Uint128.MAX + BigInteger.ONE) + } + assertThrows { + Uint256(Uint256.MAX + BigInteger.ONE) + } + } + + @Test + fun `numbers to string`() { + assertEquals( + "Felt(0xabcdef01234567890)", + Felt.fromHex("0xabcdef01234567890").toString(), + ) + assertEquals( + "NumAsHex(0xabcdef01234567890)", + NumAsHex.fromHex("0xabcdef01234567890").toString(), + ) + assertEquals( + "Uint64(0x1234567890abcdef)", + Uint64.fromHex("0x1234567890abcdef").toString(), + ) + assertEquals( + "Uint128(0xabcdef01234567890)", + Uint128.fromHex("0xabcdef01234567890").toString(), + ) + assertEquals( + "Uint256(58462017464642449753835857636044240746640)", + Uint256.fromHex("0xabcdef01234567890abcdef01234567890").toString(), + ) + } + + @Test + fun `numbers are comparable`() { + val felt1 = Felt.fromHex("0x123") + val felt2 = Felt.fromHex("0x456") + val uint64 = Uint64.fromHex("0x123") + val uint128 = Uint128.fromHex("0x456") + val uint256 = Uint256.fromHex("0x123") + val numAsHex = NumAsHex.fromHex("0x456") + + assertEquals(felt1.compareTo(uint64), 0) + assertEquals(felt1.compareTo(uint256), 0) + assertEquals(felt2.compareTo(uint128), 0) + assertEquals(felt2.compareTo(numAsHex), 0) + assertTrue(felt1 < felt2) + assertTrue(felt1 < uint128) + assertTrue(felt1 < numAsHex) + assertTrue(uint256 <= felt1) + } + + @Nested + inner class FeltTests { + @Test + fun `fromShortString short string`() { + val encoded = Felt.fromShortString("hello") + + assertEquals(Felt.fromHex("0x68656c6c6f"), encoded) + } + + @Test + fun `fromShortString too long string should fail`() { + assertThrows("Short string cannot be longer than 31 characters") { + Felt.fromShortString("a".repeat(32)) + } + } + + @Test + fun `fromShortString non ascii string should fail`() { + assertThrows("String to be encoded must be an ascii string") { + Felt.fromShortString("hello\uD83D\uDE00") + } + } + + @Test + fun `toShortString short string`() { + val decoded = Felt.fromHex("0x68656c6c6f").toShortString() + + assertEquals("hello", decoded) + } + + @Test + fun `toShortString short string - start pad with 0`() { + val decoded = Felt.fromHex("0xa68656c6c6f").toShortString() + + assertEquals("\nhello", decoded) + } + + @Test + fun `felt array is convertible to calldata`() { + val convertibleToCalldata = ArrayList() + + val feltArray1 = FeltArray(Felt(100), Felt(200)) + val feltArray2 = FeltArray(listOf(Felt(300), Felt(400))) + feltArray2.add(Felt(500)) + val emptyFeltArray = FeltArray() + + convertibleToCalldata.add(Felt(15)) + convertibleToCalldata.add(feltArray1.size.toFelt) + convertibleToCalldata.add(feltArray1) + convertibleToCalldata.add(feltArray2.size.toFelt) + convertibleToCalldata.add(feltArray2) + convertibleToCalldata.add(emptyFeltArray.size.toFelt) + convertibleToCalldata.add(emptyFeltArray) + + val calldata = convertibleToCalldata.toCalldata() + + val expectedCalldata = listOf( + Felt(15), + Felt(2), Felt(100), Felt(200), + Felt(3), Felt(300), Felt(400), Felt(500), + Felt(0), + ) + assertEquals(expectedCalldata, calldata) + } + } + + @Nested + inner class Uint256Tests { + @Test + fun `create from two felts`() { + val felt1 = Felt.fromHex("0x123abc") + val felt2 = Felt.fromHex("0x456") + val uint256 = Uint256(BigInteger("377713427282241694444345814249262715910844")) + + assertEquals(uint256, Uint256(felt1, felt2)) + assertEquals(uint256, Uint256(felt1.value, felt2.value)) + assertEquals(felt1, uint256.low) + assertEquals(felt2, uint256.high) + } + + @Test + fun `get low and high`() { + val bigUint256 = Uint256(BigInteger("377713427282241694444345814249262715910844")) + + assertEquals(Felt.fromHex("0x123abc"), bigUint256.low) + assertEquals(Felt.fromHex("0x456"), bigUint256.high) + + val smallUint256 = Uint256(1000) + assertEquals(Felt.fromHex("0x3e8"), smallUint256.low) + assertEquals(Felt.fromHex("0x0"), smallUint256.high) + } + } +} diff --git a/lib/src/test/kotlin/network/account/AccountTest.kt b/lib/src/test/kotlin/network/account/AccountTest.kt index 1e860bfc3..9ccf69c05 100644 --- a/lib/src/test/kotlin/network/account/AccountTest.kt +++ b/lib/src/test/kotlin/network/account/AccountTest.kt @@ -86,10 +86,9 @@ class AccountTest { entrypoint = "put", calldata = listOf(Felt.fromHex("0x1D2C3B7A8"), Felt.fromHex("0x451")), ) - val simulationFlags = emptySet() - val estimateFeeRequest = account.estimateFee( + val estimateFeeRequest = account.estimateFeeV1( listOf(call), - simulationFlags, + skipValidate = false, ) val estimateFeeResponse = estimateFeeRequest.send().first().overallFee assertTrue(estimateFeeResponse.value > Felt.ONE.value) @@ -111,7 +110,7 @@ class AccountTest { // Chances are, the contract was compiled with a different compiler version. val classHash = Felt.fromHex("0x6d5c6e633015a1cb4637233f181a9bb9599be26ff16a8ce335822b41f98f70b") - val declareTransactionPayload = account.signDeclare( + val declareTransactionPayload = account.signDeclareV1( contractDefinition, classHash, ExecutionParams( @@ -156,7 +155,7 @@ class AccountTest { val casmContractDefinition = CasmContractDefinition(casmCode) val nonce = account.getNonce().send() - val declareTransactionPayload = account.signDeclare( + val declareTransactionPayload = account.signDeclareV2( contractDefinition, casmContractDefinition, ExecutionParams( @@ -205,7 +204,7 @@ class AccountTest { nonce = nonce, l1ResourceBounds = ResourceBounds.ZERO, ) - val declareTransactionPayload = account.signDeclare( + val declareTransactionPayload = account.signDeclareV3( sierraContractDefinition = contractDefinition, casmContractDefinition = casmContractDefinition, params = params, @@ -241,7 +240,7 @@ class AccountTest { // 3. This test sometimes fails due to getNonce receiving higher (pending) nonce than addDeclareTransaction expects val classHash = Felt.fromHex("0x6d5c6e633015a1cb4637233f181a9bb9599be26ff16a8ce335822b41f98f70b") - val declareTransactionPayload = account.signDeclare( + val declareTransactionPayload = account.signDeclareV1( contractDefinition, classHash, ExecutionParams(nonce, Felt(1000000000000000L)), @@ -276,7 +275,7 @@ class AccountTest { val contractCasmDefinition = CasmContractDefinition(casmCode) val nonce = account.getNonce().send() - val declareTransactionPayload = account.signDeclare( + val declareTransactionPayload = account.signDeclareV2( contractDefinition, contractCasmDefinition, ExecutionParams(nonce, Felt(1000000000000000L)), @@ -309,7 +308,7 @@ class AccountTest { val contractCasmDefinition = CasmContractDefinition(casmCode) val nonce = account.getNonce().send() - val declareTransactionPayload = account.signDeclare( + val declareTransactionPayload = account.signDeclareV2( contractDefinition, contractCasmDefinition, ExecutionParams(nonce, Felt(1000000000000000L)), @@ -353,7 +352,7 @@ class AccountTest { nonce = nonce, l1ResourceBounds = l1ResourceBounds, ) - val declareTransactionPayload = account.signDeclare( + val declareTransactionPayload = account.signDeclareV3( contractDefinition, contractCasmDefinition, params, @@ -384,7 +383,7 @@ class AccountTest { ), ) - val invokeRequest = account.execute(call, Felt(1000000000000000L)) + val invokeRequest = account.executeV1(call, Felt(1000000000000000L)) val invokeResponse = invokeRequest.send() Thread.sleep(20000) @@ -462,7 +461,7 @@ class AccountTest { cairoVersion, ) - val payloadForFeeEstimation = account.signDeployAccount( + val payloadForFeeEstimation = account.signDeployAccountV1( classHash = classHash, salt = salt, calldata = calldata, @@ -512,7 +511,7 @@ class AccountTest { calldata = listOf(recipientAccountAddress) + amount.toCalldata(), ) - val request = account.execute(call) + val request = account.executeV1(call) val response = request.send() Thread.sleep(15000) @@ -556,14 +555,14 @@ class AccountTest { ), ) - val transferRequest = account.execute(call) + val transferRequest = account.executeV1(call) val transferResponse = transferRequest.send() Thread.sleep(15000) val transferReceipt = provider.getTransactionReceipt(transferResponse.transactionHash).send() assertTrue(transferReceipt.isAccepted) - val payload = deployedAccount.signDeployAccount( + val payload = deployedAccount.signDeployAccountV1( classHash = classHash, salt = salt, calldata = calldata, @@ -620,7 +619,7 @@ class AccountTest { provider, cairoVersion, ) - val payloadForFeeEstimate = deployedAccount.signDeployAccount( + val payloadForFeeEstimate = deployedAccount.signDeployAccountV3( classHash = classHash, salt = salt, calldata = calldata, @@ -628,7 +627,7 @@ class AccountTest { nonce = Felt.ZERO, l1ResourceBounds = ResourceBounds.ZERO, ), - forFeeEstimate = false, // BUG: (#344) this should be true, but Pathfinder and Devnet claim that using query version produce invalid signature + forFeeEstimate = true, // BUG: (#344) this should be true, but Pathfinder and Devnet claim that using query version produce invalid signature ) val feeEstimateRequest = provider.getEstimateFee(listOf(payloadForFeeEstimate)) @@ -651,9 +650,9 @@ class AccountTest { val params = DeployAccountParamsV3( nonce = Felt.ZERO, - resourceBounds = resourceBounds, + l1ResourceBounds = resourceBounds.l1Gas, ) - val payload = deployedAccount.signDeployAccount( + val payload = deployedAccount.signDeployAccountV3( classHash = classHash, salt = salt, calldata = calldata, @@ -701,7 +700,7 @@ class AccountTest { nonce = nonce, maxFee = Felt(1_000_000_000_000_000), ) - val invokeTx = account.sign(call, params) + val invokeTx = account.signV1(call, params) val call2 = Call( contractAddress = predeployedMapContractAddress, @@ -716,7 +715,7 @@ class AccountTest { nonce = nonce.value.add(BigInteger.ONE).toFelt, maxFee = Felt(1_000_000_000_000_000), ) - val invokeTx2 = account.sign(call2, params2) + val invokeTx2 = account.signV1(call2, params2) // Use SKIP_FEE_CHARGE flag to avoid failure due to insufficient funds val simulationFlags = setOf(SimulationFlag.SKIP_FEE_CHARGE) @@ -763,7 +762,7 @@ class AccountTest { val deployedAccountAddress = ContractAddressCalculator.calculateAddressFromHash(classHash, calldata, salt) val deployedAccount = StandardAccount(deployedAccountAddress, privateKey, provider, cairoVersion) - val deployAccountTx = deployedAccount.signDeployAccount( + val deployAccountTx = deployedAccount.signDeployAccountV1( classHash = classHash, salt = salt, calldata = calldata, @@ -811,7 +810,7 @@ class AccountTest { // Chances are, the contract was compiled with a different compiler version. val classHash = Felt.fromHex("0x6d5c6e633015a1cb4637233f181a9bb9599be26ff16a8ce335822b41f98f70b") - val declareTransactionPayload = account.signDeclare( + val declareTransactionPayload = account.signDeclareV1( contractDefinition, classHash, ExecutionParams( @@ -849,7 +848,7 @@ class AccountTest { val casmContractDefinition = CasmContractDefinition(casmCode) val nonce = account.getNonce(BlockTag.LATEST).send() - val declareTransactionPayload = account.signDeclare( + val declareTransactionPayload = account.signDeclareV2( contractDefinition, casmContractDefinition, ExecutionParams( @@ -885,7 +884,7 @@ class AccountTest { val account = standardAccount val deployer = StandardDeployer(udcAddress, provider, account) - val deployment = deployer.deployContract( + val deployment = deployer.deployContractV1( classHash = classHash, constructorCalldata = emptyList(), maxFee = Felt(1000000000000000L), @@ -914,7 +913,7 @@ class AccountTest { val deployer = StandardDeployer(udcAddress, provider, account) val initialBalance = Felt(1000) - val deployment = deployer.deployContract( + val deployment = deployer.deployContractV1( classHash = classHash, constructorCalldata = listOf(initialBalance), maxFee = Felt(1000000000000000L), diff --git a/lib/src/test/kotlin/network/provider/ProviderTest.kt b/lib/src/test/kotlin/network/provider/ProviderTest.kt index bc75341aa..cec2920ea 100644 --- a/lib/src/test/kotlin/network/provider/ProviderTest.kt +++ b/lib/src/test/kotlin/network/provider/ProviderTest.kt @@ -107,8 +107,8 @@ class ProviderTest { val expectedChainId = when (network) { Network.GOERLI_INTEGRATION -> StarknetChainId.GOERLI Network.GOERLI_TESTNET -> StarknetChainId.GOERLI - Network.SEPOLIA_INTEGRATION -> StarknetChainId.SEPOLIA_INTEGRATION - Network.SEPOLIA_TESTNET -> StarknetChainId.SEPOLIA_TESTNET + Network.SEPOLIA_INTEGRATION -> StarknetChainId.INTEGRATION_SEPOLIA + Network.SEPOLIA_TESTNET -> StarknetChainId.SEPOLIA } assertEquals(expectedChainId, chainId) } diff --git a/lib/src/test/kotlin/starknet/account/StandardAccountTest.kt b/lib/src/test/kotlin/starknet/account/StandardAccountTest.kt index a85a61203..d398fd1c4 100644 --- a/lib/src/test/kotlin/starknet/account/StandardAccountTest.kt +++ b/lib/src/test/kotlin/starknet/account/StandardAccountTest.kt @@ -7,6 +7,7 @@ import com.swmansion.starknet.data.ContractAddressCalculator import com.swmansion.starknet.data.selectorFromName import com.swmansion.starknet.data.types.* import com.swmansion.starknet.data.types.transactions.* +import com.swmansion.starknet.extensions.toFelt import com.swmansion.starknet.provider.exceptions.RequestFailedException import com.swmansion.starknet.provider.rpc.JsonRpcProvider import com.swmansion.starknet.service.http.HttpResponse @@ -119,12 +120,9 @@ class StandardAccountTest { @Test fun `get nonce twice`() { val startNonce = account.getNonce().send() - val call = Call( - contractAddress = balanceContractAddress, - entrypoint = "increase_balance", - calldata = listOf(Felt(10)), - ) - account.execute(call).send() + val call = Call(balanceContractAddress, "increase_balance", listOf(Felt(10))) + + account.executeV1(call).send() val endNonce = account.getNonce().send() assertEquals( @@ -138,136 +136,165 @@ class StandardAccountTest { inner class InvokeEstimateTest { @Test fun `estimate fee for invoke v1 transaction`() { - val call = Call( - contractAddress = balanceContractAddress, - entrypoint = "increase_balance", - calldata = listOf(Felt(10)), - ) + val call = Call(balanceContractAddress, "increase_balance", listOf(Felt(10))) - val request = account.estimateFee(call) - val response = request.send() - val feeEstimate = response.first() + val request = account.estimateFeeV1(call) + val feeEstimate = request.send().first() - assertNotEquals(Felt.ZERO, feeEstimate.gasPrice) - assertNotEquals(Felt.ZERO, feeEstimate.gasConsumed) assertNotEquals(Felt.ZERO, feeEstimate.overallFee) assertEquals(feeEstimate.gasPrice.value.multiply(feeEstimate.gasConsumed.value), feeEstimate.overallFee.value) } @Test fun `estimate fee for invoke v3 transaction`() { - val call = Call( - contractAddress = balanceContractAddress, - entrypoint = "increase_balance", - calldata = listOf(Felt(10)), - ) + val call = Call(balanceContractAddress, "increase_balance", listOf(Felt(10))) - val simulationFlags = emptySet() val request = account.estimateFeeV3( listOf(call), - simulationFlags, + skipValidate = false, ) - val response = request.send() - val feeEstimate = response.first() + val feeEstimate = request.send().first() - assertNotEquals(Felt.ZERO, feeEstimate.gasPrice) - assertNotEquals(Felt.ZERO, feeEstimate.gasConsumed) assertNotEquals(Felt.ZERO, feeEstimate.overallFee) assertEquals(feeEstimate.gasPrice.value.multiply(feeEstimate.gasConsumed.value), feeEstimate.overallFee.value) } @Test - fun `estimate fee for invoke transaction at latest block tag`() { - val call = Call( - contractAddress = balanceContractAddress, - entrypoint = "increase_balance", - calldata = listOf(Felt(10)), + fun `estimate fee with skip validate flag`() { + val call = Call(balanceContractAddress, "increase_balance", listOf(Felt(10))) + + val nonce = account.getNonce().send() + val invokeTxV1Payload = account.signV1( + call = call, + params = ExecutionParams(nonce, Felt.ZERO), + forFeeEstimate = true, ) + val invokeTxV3Payload = account.signV3( + call = call, + params = InvokeParamsV3(nonce.value.add(BigInteger.ONE).toFelt, ResourceBounds.ZERO), + forFeeEstimate = true, + ) + assertEquals(Felt.fromHex("0x100000000000000000000000000000001"), invokeTxV1Payload.version) + assertEquals(Felt.fromHex("0x100000000000000000000000000000003"), invokeTxV3Payload.version) - val request = account.estimateFee(call, BlockTag.LATEST) - val response = request.send() - val feeEstimate = response.first() + val invokeTxV1PayloadWithoutSignature = invokeTxV1Payload.copy(signature = emptyList()) + val invokeTxV3PayloadWithoutSignature = invokeTxV3Payload.copy(signature = emptyList()) + + val request = provider.getEstimateFee( + payload = listOf(invokeTxV1PayloadWithoutSignature, invokeTxV3PayloadWithoutSignature), + simulationFlags = setOf(SimulationFlagForEstimateFee.SKIP_VALIDATE), + ) + + val feeEstimates = request.send() + feeEstimates.forEach { + assertNotEquals(Felt.ZERO, it.overallFee) + assertEquals(it.gasPrice.value.multiply(it.gasConsumed.value), it.overallFee.value) + } + } + + @Test + fun `estimate fee for invoke v1 transaction at latest block tag`() { + val call = Call(balanceContractAddress, "increase_balance", listOf(Felt(10))) + + val request = account.estimateFeeV1(call, BlockTag.LATEST) + val feeEstimate = request.send().first() - assertNotEquals(Felt.ZERO, feeEstimate.gasPrice) - assertNotEquals(Felt.ZERO, feeEstimate.gasConsumed) assertNotEquals(Felt.ZERO, feeEstimate.overallFee) assertEquals(feeEstimate.gasPrice.value.multiply(feeEstimate.gasConsumed.value), feeEstimate.overallFee.value) } } - @Test - fun `estimate fee for declare v1 transaction`() { - val contractCode = Path.of("src/test/resources/contracts_v0/target/release/balance.json").readText() - val contractDefinition = Cairo0ContractDefinition(contractCode) - val nonce = account.getNonce().send() + @Nested + inner class DeclareEstimateTest { + @Test + fun `estimate fee for declare v1 transaction`() { + val contractCode = Path.of("src/test/resources/contracts_v0/target/release/balance.json").readText() + val contractDefinition = Cairo0ContractDefinition(contractCode) + val nonce = account.getNonce().send() - // Note to future developers experiencing failures in this test. Compiled contract format sometimes - // changes, this causes changes in the class hash. - // If this test starts randomly falling, try recalculating class hash. - val classHash = Felt.fromHex("0x6d5c6e633015a1cb4637233f181a9bb9599be26ff16a8ce335822b41f98f70b") - val declareTransactionPayload = account.signDeclare( - contractDefinition, - classHash, - ExecutionParams(nonce, Felt(1000000000000000)), - ) + // Note to future developers experiencing failures in this test. Compiled contract format sometimes + // changes, this causes changes in the class hash. + // If this test starts randomly falling, try recalculating class hash. + val classHash = Felt.fromHex("0x6d5c6e633015a1cb4637233f181a9bb9599be26ff16a8ce335822b41f98f70b") + val declareTransactionPayload = account.signDeclareV1( + contractDefinition = contractDefinition, + classHash = classHash, + params = ExecutionParams(nonce, Felt.ZERO), + forFeeEstimate = true, + ) - val signedTransaction = TransactionFactory.makeDeclareV1Transaction( - classHash = classHash, - senderAddress = declareTransactionPayload.senderAddress, - contractDefinition = declareTransactionPayload.contractDefinition, - chainId = provider.getChainId().send(), - nonce = nonce, - maxFee = declareTransactionPayload.maxFee, - signature = declareTransactionPayload.signature, - version = declareTransactionPayload.version, - ) + assertEquals(Felt.fromHex("0x100000000000000000000000000000001"), declareTransactionPayload.version) - val request = provider.getEstimateFee( - listOf(signedTransaction.toPayload()), - BlockTag.LATEST, - emptySet(), - ) - val response = request.send() - val feeEstimate = response.first() + val request = provider.getEstimateFee(payload = listOf(declareTransactionPayload), simulationFlags = emptySet()) + val feeEstimate = request.send().first() - val txWithoutSignature = signedTransaction.copy(signature = emptyList()) - val request2 = provider.getEstimateFee( - listOf(txWithoutSignature.toPayload()), - BlockTag.LATEST, - setOf(SimulationFlagForEstimateFee.SKIP_VALIDATE), - ) - val response2 = request2.send() - val feeEstimate2 = response2.first() - - listOf(feeEstimate, feeEstimate2).forEach { - assertNotEquals(Felt.ZERO, it.gasPrice) - assertNotEquals(Felt.ZERO, it.gasConsumed) - assertNotEquals(Felt.ZERO, it.overallFee) - assertEquals(it.gasPrice.value.multiply(it.gasConsumed.value), it.overallFee.value) + assertNotEquals(Felt.ZERO, feeEstimate.overallFee) + assertEquals(feeEstimate.gasPrice.value.multiply(feeEstimate.gasConsumed.value), feeEstimate.overallFee.value) } - assertThrows(RequestFailedException::class.java) { - provider.getEstimateFee( - listOf(txWithoutSignature.toPayload()), - BlockTag.LATEST, - emptySet(), - ).send() + @Test + fun `estimate fee for declare v2 transaction`() { + 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() + + val contractDefinition = Cairo1ContractDefinition(contractCode) + val contractCasmDefinition = CasmContractDefinition(casmCode) + val nonce = account.getNonce().send() + + val declareTransactionPayload = account.signDeclareV2( + sierraContractDefinition = contractDefinition, + casmContractDefinition = contractCasmDefinition, + params = ExecutionParams(nonce, Felt.ZERO), + forFeeEstimate = true, + ) + + assertEquals(Felt.fromHex("0x100000000000000000000000000000002"), declareTransactionPayload.version) + + val request = provider.getEstimateFee(payload = listOf(declareTransactionPayload), simulationFlags = emptySet()) + val feeEstimate = request.send().first() + + assertNotEquals(Felt.ZERO, feeEstimate.overallFee) + assertEquals(feeEstimate.gasPrice.value.multiply(feeEstimate.gasConsumed.value), feeEstimate.overallFee.value) } + + @Test + fun `estimate fee for declare v3 transaction`() { + 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() + + val contractDefinition = Cairo1ContractDefinition(contractCode) + val contractCasmDefinition = CasmContractDefinition(casmCode) + val nonce = account.getNonce().send() + + val params = DeclareParamsV3(nonce = nonce, l1ResourceBounds = ResourceBounds.ZERO) + val declareTransactionPayload = account.signDeclareV3( + contractDefinition, + contractCasmDefinition, + params, + true, + ) + + assertEquals(Felt.fromHex("0x100000000000000000000000000000003"), declareTransactionPayload.version) + + val request = provider.getEstimateFee(payload = listOf(declareTransactionPayload), simulationFlags = emptySet()) + val feeEstimate = request.send().first() + + assertNotEquals(Felt.ZERO, feeEstimate.overallFee) + assertEquals(feeEstimate.gasPrice.value.multiply(feeEstimate.gasConsumed.value), feeEstimate.overallFee.value) } } - // TODO: Use message mocking instead of deploying l1l2 contract. - // This is planned for when Cairo 0 support is dropped, provided that devnet supports message mocking by then. @Test fun `estimate message fee`() { // Note to future developers experiencing failures in this test. // Compiled contract format sometimes changes, this causes changes in the class hash. // If this test starts randomly falling, try recalculating class hash. + // TODO: Migrate l1l2 contract to Cairo 1. val l1l2ContractCode = Path.of("src/test/resources/contracts_v0/target/release/l1l2.json").readText() val l1l2ContractDefinition = Cairo0ContractDefinition(l1l2ContractCode) val classHash = Felt.fromHex("0x310b77cf1190f2555fca715a990f9ff9f5c42e1b30b42cc3fdb573b8ab95fc1") val nonce = account.getNonce().send() - val declareTransactionPayload = account.signDeclare(l1l2ContractDefinition, classHash, ExecutionParams(nonce, Felt(1000000000000000))) + val declareTransactionPayload = account.signDeclareV1(l1l2ContractDefinition, classHash, ExecutionParams(nonce, Felt(1000000000000000))) val l2ContractClassHash = provider.declareContract(declareTransactionPayload).send().classHash val l2ContractAddress = devnetClient.deployContract( classHash = l2ContractClassHash, @@ -297,109 +324,111 @@ class StandardAccountTest { assertEquals(response.gasPrice.value.multiply(response.gasConsumed.value), response.overallFee.value) } - @Test - fun `sign and send declare v1 transaction`() { - val contractCode = Path.of("src/test/resources/contracts_v0/target/release/balance.json").readText() - val contractDefinition = Cairo0ContractDefinition(contractCode) - val nonce = account.getNonce().send() + @Nested + inner class DeclareTest { + @Test + fun `sign and send declare v1 transaction`() { + val contractCode = Path.of("src/test/resources/contracts_v0/target/release/balance.json").readText() + val contractDefinition = Cairo0ContractDefinition(contractCode) + val nonce = account.getNonce().send() - // Note to future developers experiencing failures in this test. - // 1. Compiled contract format sometimes changes, this causes changes in the class hash. - // If this test starts randomly falling, try recalculating class hash. - // 2. If it fails on CI, make sure to delete the compiled contracts before running this test. - // Chances are, the contract was compiled with a different compiler version. - - val classHash = Felt.fromHex("0x6d5c6e633015a1cb4637233f181a9bb9599be26ff16a8ce335822b41f98f70b") - val declareTransactionPayload = account.signDeclare( - contractDefinition, - classHash, - ExecutionParams(nonce, Felt(1000000000000000L)), - ) + // Note to future developers experiencing failures in this test. + // 1. Compiled contract format sometimes changes, this causes changes in the class hash. + // If this test starts randomly falling, try recalculating class hash. + // 2. If it fails on CI, make sure to delete the compiled contracts before running this test. + // Chances are, the contract was compiled with a different compiler version. + + val classHash = Felt.fromHex("0x6d5c6e633015a1cb4637233f181a9bb9599be26ff16a8ce335822b41f98f70b") + val declareTransactionPayload = account.signDeclareV1( + contractDefinition, + classHash, + ExecutionParams(nonce, Felt(1000000000000000L)), + ) - val request = provider.declareContract(declareTransactionPayload) - val result = request.send() + val request = provider.declareContract(declareTransactionPayload) + val result = request.send() - val receipt = provider.getTransactionReceipt(result.transactionHash).send() + val receipt = provider.getTransactionReceipt(result.transactionHash).send() - assertTrue(receipt.isAccepted) - } + assertTrue(receipt.isAccepted) + } - @Test - fun `sign and send declare v2 transaction`() { - 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() + @Test + fun `sign and send declare v2 transaction`() { + 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() - val contractDefinition = Cairo1ContractDefinition(contractCode) - val contractCasmDefinition = CasmContractDefinition(casmCode) - val nonce = account.getNonce().send() + val contractDefinition = Cairo1ContractDefinition(contractCode) + val contractCasmDefinition = CasmContractDefinition(casmCode) + val nonce = account.getNonce().send() - val declareTransactionPayload = account.signDeclare( - contractDefinition, - contractCasmDefinition, - ExecutionParams(nonce, Felt(1000000000000000L)), - ) - val request = provider.declareContract(declareTransactionPayload) - val result = request.send() + val declareTransactionPayload = account.signDeclareV2( + contractDefinition, + contractCasmDefinition, + ExecutionParams(nonce, Felt(1000000000000000L)), + ) + val request = provider.declareContract(declareTransactionPayload) + val result = request.send() - val receipt = provider.getTransactionReceipt(result.transactionHash).send() + val receipt = provider.getTransactionReceipt(result.transactionHash).send() - assertTrue(receipt.isAccepted) - } + assertTrue(receipt.isAccepted) + } - @Test - fun `sign and send declare v2 transaction (cairo compiler v2)`() { - 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() + @Test + fun `sign and send declare v2 transaction (cairo compiler v2)`() { + 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() - val contractDefinition = Cairo2ContractDefinition(contractCode) - val contractCasmDefinition = CasmContractDefinition(casmCode) - val nonce = account.getNonce().send() + val contractDefinition = Cairo2ContractDefinition(contractCode) + val contractCasmDefinition = CasmContractDefinition(casmCode) + val nonce = account.getNonce().send() - val declareTransactionPayload = account.signDeclare( - contractDefinition, - contractCasmDefinition, - ExecutionParams(nonce, Felt(1000000000000000)), - ) - val request = provider.declareContract(declareTransactionPayload) - val result = request.send() + val declareTransactionPayload = account.signDeclareV2( + contractDefinition, + contractCasmDefinition, + ExecutionParams(nonce, Felt(1000000000000000)), + ) + val request = provider.declareContract(declareTransactionPayload) + val result = request.send() - val receipt = provider.getTransactionReceipt(result.transactionHash).send() + val receipt = provider.getTransactionReceipt(result.transactionHash).send() - assertTrue(receipt.isAccepted) - } + assertTrue(receipt.isAccepted) + } - @Test - fun `sign and send declare v3 transaction`() { - 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"), - ) - val contractCode = Path.of("src/test/resources/contracts_v2/target/release/ContractsV2_SaltedCounterContract.sierra.json").readText() - val casmCode = Path.of("src/test/resources/contracts_v2/target/release/ContractsV2_SaltedCounterContract.casm.json").readText() + @Test + fun `sign and send declare v3 transaction`() { + 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"), + ) + val contractCode = Path.of("src/test/resources/contracts_v2/target/release/ContractsV2_SaltedCounterContract.sierra.json").readText() + val casmCode = Path.of("src/test/resources/contracts_v2/target/release/ContractsV2_SaltedCounterContract.casm.json").readText() - val contractDefinition = Cairo2ContractDefinition(contractCode) - val contractCasmDefinition = CasmContractDefinition(casmCode) - val nonce = account.getNonce().send() + val contractDefinition = Cairo2ContractDefinition(contractCode) + val contractCasmDefinition = CasmContractDefinition(casmCode) + val nonce = account.getNonce().send() - val params = DeclareParamsV3( - nonce = nonce, - l1ResourceBounds = ResourceBounds( - maxAmount = Uint64(20000), - maxPricePerUnit = Uint128(120000000000), - ), - ) - val declareTransactionPayload = account.signDeclare( - contractDefinition, - contractCasmDefinition, - params, - false, - ) - val request = provider.declareContract(declareTransactionPayload) - val result = request.send() + val params = DeclareParamsV3( + nonce = nonce, + l1ResourceBounds = ResourceBounds( + maxAmount = Uint64(20000), + maxPricePerUnit = Uint128(120000000000), + ), + ) + val declareTransactionPayload = account.signDeclareV3( + contractDefinition, + contractCasmDefinition, + params, + ) + val request = provider.declareContract(declareTransactionPayload) + val result = request.send() - val receipt = provider.getTransactionReceipt(result.transactionHash).send() + val receipt = provider.getTransactionReceipt(result.transactionHash).send() - assertTrue(receipt.isAccepted) + assertTrue(receipt.isAccepted) + } } @Test @@ -462,7 +491,7 @@ class StandardAccountTest { nonce = account.getNonce().send(), ) - val payload = account.sign(call, params) + val payload = account.signV1(call, params) val request = provider.invokeFunction(payload) val response = request.send() @@ -479,7 +508,7 @@ class StandardAccountTest { entrypoint = "increase_balance", ) - val params = ExecutionParamsV3( + val params = InvokeParamsV3( nonce = account.getNonce().send(), l1ResourceBounds = ResourceBounds( maxAmount = Uint64(20000), @@ -487,7 +516,7 @@ class StandardAccountTest { ), ) - val payload = account.sign(call, params) + val payload = account.signV3(call, params) val request = provider.invokeFunction(payload) val response = request.send() @@ -504,7 +533,7 @@ class StandardAccountTest { calldata = listOf(Felt(10)), ) - val result = account.execute(call).send() + val result = account.executeV1(call).send() val receipt = provider.getTransactionReceipt(result.transactionHash).send() @@ -537,7 +566,7 @@ class StandardAccountTest { ) val maxFee = Felt(10000000000000000L) - val result = account.execute(call, maxFee).send() + val result = account.executeV1(call, maxFee).send() val receipt = provider.getTransactionReceipt(result.transactionHash).send() @@ -580,7 +609,7 @@ class StandardAccountTest { nonce = account.getNonce().send(), ) - val payload = account.sign(listOf(call, call, call), params) + val payload = account.signV1(listOf(call, call, call), params) val response = provider.invokeFunction(payload).send() val receipt = provider.getTransactionReceipt(response.transactionHash).send() @@ -596,7 +625,7 @@ class StandardAccountTest { calldata = listOf(Felt(10)), ) - val params = ExecutionParamsV3( + val params = InvokeParamsV3( nonce = account.getNonce().send(), l1ResourceBounds = ResourceBounds( maxAmount = Uint64(20000), @@ -604,7 +633,7 @@ class StandardAccountTest { ), ) - val payload = account.sign(listOf(call, call, call), params) + val payload = account.signV3(listOf(call, call, call), params) val response = provider.invokeFunction(payload).send() val receipt = provider.getTransactionReceipt(response.transactionHash).send() @@ -626,7 +655,7 @@ class StandardAccountTest { calldata = listOf(Felt(10)), ) - val result = account.execute(listOf(call1, call2)).send() + val result = account.executeV1(listOf(call1, call2)).send() val receipt = provider.getTransactionReceipt(result.transactionHash).send() @@ -662,7 +691,7 @@ class StandardAccountTest { calldata = listOf(Felt(10)), ) - val result = account.execute(call).send() + val result = account.executeV1(call).send() val receipt = provider.getTransactionReceipt(result.transactionHash).send() assertTrue(receipt.isAccepted) @@ -673,7 +702,7 @@ class StandardAccountTest { calldata = listOf(Felt(20)), ) - val result2 = account.execute(call2).send() + val result2 = account.executeV1(call2).send() val receipt2 = provider.getTransactionReceipt(result2.transactionHash).send() assertTrue(receipt2.isAccepted) @@ -731,7 +760,7 @@ class StandardAccountTest { cairoVersion = Felt.ONE, ) val params = ExecutionParams(Felt.ZERO, Felt.ZERO) - val signedTx = account.sign(listOf(call1, call2, call3), params) + val signedTx = account.signV1(listOf(call1, call2, call3), params) val expectedCalldata = listOf( Felt(3), @@ -753,198 +782,195 @@ class StandardAccountTest { assertEquals(expectedCalldata, signedTx.calldata) - val signedEmptyTx = account.sign(listOf(), params) + val signedEmptyTx = account.signV1(listOf(), params) assertEquals(listOf(Felt.ZERO), signedEmptyTx.calldata) } } - @Test - fun `estimate deploy account v1 fee`() { - val privateKey = Felt(11112) - val publicKey = StarknetCurve.getPublicKey(privateKey) + @Nested + inner class DeployAccountEstimateTest { + @Test + fun `estimate fee for deploy account v1 transaction`() { + val privateKey = Felt(11112) + val publicKey = StarknetCurve.getPublicKey(privateKey) + + val salt = Felt.ONE + val calldata = listOf(publicKey) + val address = ContractAddressCalculator.calculateAddressFromHash( + classHash = accountContractClassHash, + calldata = calldata, + salt = salt, + ) - val salt = Felt.ONE - val calldata = listOf(publicKey) - val address = ContractAddressCalculator.calculateAddressFromHash( - classHash = accountContractClassHash, - calldata = calldata, - salt = salt, - ) + val account = StandardAccount( + address, + privateKey, + provider, + ) + val payloadForFeeEstimation = account.signDeployAccountV1( + classHash = accountContractClassHash, + salt = salt, + calldata = calldata, + maxFee = Felt.ZERO, + nonce = Felt.ZERO, + forFeeEstimate = true, + ) + assertEquals(Felt.fromHex("0x100000000000000000000000000000001"), payloadForFeeEstimation.version) - val account = StandardAccount( - address, - privateKey, - provider, - ) - val payloadForFeeEstimation = account.signDeployAccount( - classHash = accountContractClassHash, - salt = salt, - calldata = calldata, - maxFee = Felt.ZERO, - nonce = Felt.ZERO, - forFeeEstimate = true, - ) - assertEquals( - payloadForFeeEstimation.version, - Felt(BigInteger("340282366920938463463374607431768211457")), - ) + val feePayload = provider.getEstimateFee(listOf(payloadForFeeEstimation)).send() + assertTrue(feePayload.first().overallFee.value > Felt.ONE.value) + } - val feePayload = provider.getEstimateFee(listOf(payloadForFeeEstimation)).send() - assertTrue(feePayload.first().overallFee.value > Felt.ONE.value) + @Test + fun `estimate fee for deploy account v3 transaction`() { + val privateKey = Felt(22223) + val publicKey = StarknetCurve.getPublicKey(privateKey) + + val salt = Felt(2) + val calldata = listOf(publicKey) + val address = ContractAddressCalculator.calculateAddressFromHash( + classHash = accountContractClassHash, + calldata = calldata, + salt = salt, + ) + val account = StandardAccount( + address, + privateKey, + provider, + ) + val params = DeployAccountParamsV3( + nonce = Felt.ZERO, + l1ResourceBounds = ResourceBounds.ZERO, + ) + val payloadForFeeEstimation = account.signDeployAccountV3( + classHash = accountContractClassHash, + salt = salt, + calldata = calldata, + params = params, + forFeeEstimate = true, + ) + + assertEquals(Felt.fromHex("0x100000000000000000000000000000003"), payloadForFeeEstimation.version) + + val feePayload = provider.getEstimateFee(listOf(payloadForFeeEstimation)).send() + assertTrue(feePayload.first().overallFee.value > Felt.ONE.value) + } } - @Test - fun `estimate deploy account v3 fee`() { - val privateKey = Felt(22223) - val publicKey = StarknetCurve.getPublicKey(privateKey) + @Nested + inner class DeployAccountTest { + @Test + fun `sign and send deploy account v1 transaction`() { + val privateKey = Felt(11111) + val publicKey = StarknetCurve.getPublicKey(privateKey) + + val salt = Felt.ONE + val calldata = listOf(publicKey) + val address = ContractAddressCalculator.calculateAddressFromHash( + classHash = accountContractClassHash, + calldata = calldata, + salt = salt, + ) + devnetClient.prefundAccountEth(address) - val salt = Felt(2) - val calldata = listOf(publicKey) - val address = ContractAddressCalculator.calculateAddressFromHash( - classHash = accountContractClassHash, - calldata = calldata, - salt = salt, - ) - val account = StandardAccount( - address, - privateKey, - provider, - ) - val params = DeployAccountParamsV3( - nonce = Felt.ZERO, - l1ResourceBounds = ResourceBounds.ZERO, - ) - val payloadForFeeEstimation = account.signDeployAccount( - classHash = accountContractClassHash, - salt = salt, - calldata = calldata, - params = params, - forFeeEstimate = true, - ) + val account = StandardAccount( + address, + privateKey, + provider, + ) + val payload = account.signDeployAccountV1( + classHash = accountContractClassHash, + salt = salt, + calldata = calldata, + // 10*fee from estimate deploy account fee + maxFee = Felt.fromHex("0x11fcc58c7f7000"), + ) - val feePayload = provider.getEstimateFee(listOf(payloadForFeeEstimation)).send() - assertTrue(feePayload.first().overallFee.value > Felt.ONE.value) - } + val response = provider.deployAccount(payload).send() - @Test - fun `sing and send deploy account v1 transaction`() { - val privateKey = Felt(11111) - val publicKey = StarknetCurve.getPublicKey(privateKey) + // Make sure the address matches the calculated one + assertEquals(address, response.address) - val salt = Felt.ONE - val calldata = listOf(publicKey) - val address = ContractAddressCalculator.calculateAddressFromHash( - classHash = accountContractClassHash, - calldata = calldata, - salt = salt, - ) - devnetClient.prefundAccountEth(address) + // Make sure tx matches what we sent + val tx = provider.getTransaction(response.transactionHash).send() as DeployAccountTransactionV1 + assertEquals(payload.classHash, tx.classHash) + assertEquals(payload.salt, tx.contractAddressSalt) + assertEquals(payload.constructorCalldata, tx.constructorCalldata) + assertEquals(payload.version, tx.version) + assertEquals(payload.nonce, tx.nonce) + assertEquals(payload.maxFee, tx.maxFee) + assertEquals(payload.signature, tx.signature) - val account = StandardAccount( - address, - privateKey, - provider, - ) - val payload = account.signDeployAccount( - classHash = accountContractClassHash, - salt = salt, - calldata = calldata, - // 10*fee from estimate deploy account fee - maxFee = Felt.fromHex("0x11fcc58c7f7000"), - ) + // Invoke function to make sure the account was deployed properly + val call = Call(balanceContractAddress, "increase_balance", listOf(Felt(10))) + val result = account.executeV1(call).send() - val response = provider.deployAccount(payload).send() - - // Make sure the address matches the calculated one - assertEquals(address, response.address) - - // Make sure tx matches what we sent - val tx = provider.getTransaction(response.transactionHash).send() as DeployAccountTransactionV1 - assertEquals(payload.classHash, tx.classHash) - assertEquals(payload.salt, tx.contractAddressSalt) - assertEquals(payload.constructorCalldata, tx.constructorCalldata) - assertEquals(payload.version, tx.version) - assertEquals(payload.nonce, tx.nonce) - assertEquals(payload.maxFee, tx.maxFee) - assertEquals(payload.signature, tx.signature) - - // Invoke function to make sure the account was deployed properly - val call = Call( - contractAddress = balanceContractAddress, - entrypoint = "increase_balance", - calldata = listOf(Felt(10)), - ) - val result = account.execute(call).send() + val receipt = provider.getTransactionReceipt(result.transactionHash).send() - val receipt = provider.getTransactionReceipt(result.transactionHash).send() + assertTrue(receipt.isAccepted) + } - assertTrue(receipt.isAccepted) - } + @Test + fun `sign and send deploy account v3 transaction`() { + val privateKey = Felt(22222) + val publicKey = StarknetCurve.getPublicKey(privateKey) + + val salt = Felt(2) + val calldata = listOf(publicKey) + val address = ContractAddressCalculator.calculateAddressFromHash( + classHash = accountContractClassHash, + calldata = calldata, + salt = salt, + ) - @Test - fun `sign and send deploy account v3 transaction`() { - val privateKey = Felt(22222) - val publicKey = StarknetCurve.getPublicKey(privateKey) + val newAccount = StandardAccount( + address, + privateKey, + provider, + ) + val l1ResourceBounds = ResourceBounds( + maxAmount = Uint64(20000), + maxPricePerUnit = Uint128(120000000000), + ) + val params = DeployAccountParamsV3( + nonce = Felt.ZERO, + l1ResourceBounds = l1ResourceBounds, + ) - val salt = Felt(2) - val calldata = listOf(publicKey) - val address = ContractAddressCalculator.calculateAddressFromHash( - classHash = accountContractClassHash, - calldata = calldata, - salt = salt, - ) + // Prefund the new account address with STRK + devnetClient.prefundAccountStrk(address) - val newAccount = StandardAccount( - address, - privateKey, - provider, - ) - val l1ResourceBounds = ResourceBounds( - maxAmount = Uint64(20000), - maxPricePerUnit = Uint128(120000000000), - ) - val params = DeployAccountParamsV3( - nonce = Felt.ZERO, - l1ResourceBounds = l1ResourceBounds, - ) + val payload = newAccount.signDeployAccountV3( + classHash = accountContractClassHash, + salt = salt, + calldata = calldata, + params = params, + forFeeEstimate = false, + ) - // Prefund the new account address with STRK - devnetClient.prefundAccountStrk(address) + val response = provider.deployAccount(payload).send() - val payload = newAccount.signDeployAccount( - classHash = accountContractClassHash, - salt = salt, - calldata = calldata, - params = params, - forFeeEstimate = false, - ) + // Make sure the address matches the calculated one + assertEquals(address, response.address) - val response = provider.deployAccount(payload).send() - - // Make sure the address matches the calculated one - assertEquals(address, response.address) - - // Make sure tx matches what we sent - val tx = provider.getTransaction(response.transactionHash).send() as DeployAccountTransactionV3 - assertEquals(payload.classHash, tx.classHash) - assertEquals(payload.salt, tx.contractAddressSalt) - assertEquals(payload.constructorCalldata, tx.constructorCalldata) - assertEquals(payload.version, tx.version) - assertEquals(payload.nonce, tx.nonce) - assertEquals(payload.signature, tx.signature) - - // Invoke function to make sure the account was deployed properly - val call = Call( - contractAddress = balanceContractAddress, - entrypoint = "increase_balance", - calldata = listOf(Felt(10)), - ) - val result = newAccount.executeV3(call).send() + // Make sure tx matches what we sent + val tx = provider.getTransaction(response.transactionHash).send() as DeployAccountTransactionV3 + assertEquals(payload.classHash, tx.classHash) + assertEquals(payload.salt, tx.contractAddressSalt) + assertEquals(payload.constructorCalldata, tx.constructorCalldata) + assertEquals(payload.version, tx.version) + assertEquals(payload.nonce, tx.nonce) + assertEquals(payload.signature, tx.signature) + + // Invoke function to make sure the account was deployed properly + val call = Call(balanceContractAddress, "increase_balance", listOf(Felt(10))) + val result = newAccount.executeV3(call).send() - val receipt = provider.getTransactionReceipt(result.transactionHash).send() + val receipt = provider.getTransactionReceipt(result.transactionHash).send() - assertTrue(receipt.isAccepted) + assertTrue(receipt.isAccepted) + } } @Test @@ -965,7 +991,7 @@ class StandardAccountTest { privateKey, provider, ) - val payloadForFeeEstimation = account.signDeployAccount( + val payloadForFeeEstimation = account.signDeployAccountV1( classHash = accountContractClassHash, salt = salt, calldata = calldata, @@ -973,310 +999,406 @@ class StandardAccountTest { nonce = Felt.ONE, forFeeEstimate = true, ) - assertEquals( - payloadForFeeEstimation.version, - Felt(BigInteger("340282366920938463463374607431768211457")), - ) + assertEquals(Felt.fromHex("0x100000000000000000000000000000001"), payloadForFeeEstimation.version) assertThrows(RequestFailedException::class.java) { provider.deployAccount(payloadForFeeEstimation).send() } } - @Test - fun `simulate invoke and deploy account transactions`() { - val account = StandardAccount(accountAddress, signer, provider) - devnetClient.prefundAccountEth(accountAddress) + @Nested + inner class SimulateTransactionsTest { + @Test + fun `simulate invoke v1 and deploy account v1 transactions`() { + val account = StandardAccount(accountAddress, signer, provider) + devnetClient.prefundAccountEth(accountAddress) - val nonce = account.getNonce().send() - val call = Call( - contractAddress = balanceContractAddress, - entrypoint = "increase_balance", - calldata = listOf(Felt(1000)), - ) - val params = ExecutionParams(nonce, Felt(5_482_000_000_000_00)) + val nonce = account.getNonce().send() + val call = Call( + contractAddress = balanceContractAddress, + entrypoint = "increase_balance", + calldata = listOf(Felt(1000)), + ) + val params = ExecutionParams(nonce, Felt(5_482_000_000_000_00)) - val invokeTx = account.sign(call, params) + val invokeTx = account.signV1(call, params) - val privateKey = Felt(22222) - val publicKey = StarknetCurve.getPublicKey(privateKey) - val salt = Felt.ONE - val calldata = listOf(publicKey) + val privateKey = Felt(22222) + val publicKey = StarknetCurve.getPublicKey(privateKey) + val salt = Felt.ONE + val calldata = listOf(publicKey) - val newAccountAddress = ContractAddressCalculator.calculateAddressFromHash( - classHash = accountContractClassHash, - calldata = calldata, - salt = salt, - ) - val newAccount = StandardAccount( - newAccountAddress, - privateKey, - provider, - ) - devnetClient.prefundAccountEth(newAccountAddress) - val deployAccountTx = newAccount.signDeployAccount( - classHash = accountContractClassHash, - salt = salt, - calldata = calldata, - maxFee = Felt(4_482_000_000_000_00), - ) + val newAccountAddress = ContractAddressCalculator.calculateAddressFromHash( + classHash = accountContractClassHash, + calldata = calldata, + salt = salt, + ) + val newAccount = StandardAccount( + newAccountAddress, + privateKey, + provider, + ) + devnetClient.prefundAccountEth(newAccountAddress) + val deployAccountTx = newAccount.signDeployAccountV1( + classHash = accountContractClassHash, + salt = salt, + calldata = calldata, + maxFee = Felt(4_482_000_000_000_00), + ) - val simulationFlags = setOf() - val simulationResult = provider.simulateTransactions( - transactions = listOf(invokeTx, deployAccountTx), - blockTag = BlockTag.LATEST, - simulationFlags = simulationFlags, - ).send() - assertEquals(2, simulationResult.size) - assertTrue(simulationResult[0].transactionTrace is InvokeTransactionTraceBase) - assertTrue(simulationResult[0].transactionTrace is InvokeTransactionTrace) - assertTrue(simulationResult[1].transactionTrace is DeployAccountTransactionTrace) - - val invokeTxWithoutSignature = InvokeTransactionV1Payload(invokeTx.senderAddress, invokeTx.calldata, emptyList(), invokeTx.maxFee, invokeTx.version, invokeTx.nonce) - val deployAccountTxWithoutSignature = DeployAccountTransactionV1Payload(deployAccountTx.classHash, deployAccountTx.salt, deployAccountTx.constructorCalldata, deployAccountTx.version, deployAccountTx.nonce, deployAccountTx.maxFee, emptyList()) - - val simulationFlags2 = setOf(SimulationFlag.SKIP_VALIDATE) - val simulationResult2 = provider.simulateTransactions( - transactions = listOf(invokeTxWithoutSignature, deployAccountTxWithoutSignature), - blockTag = BlockTag.LATEST, - simulationFlags = simulationFlags2, - ).send() + val simulationFlags = setOf() + val simulationResult = provider.simulateTransactions( + transactions = listOf(invokeTx, deployAccountTx), + blockTag = BlockTag.PENDING, + simulationFlags = simulationFlags, + ).send() + assertEquals(2, simulationResult.size) + assertTrue(simulationResult[0].transactionTrace is InvokeTransactionTraceBase) + assertTrue(simulationResult[0].transactionTrace is InvokeTransactionTrace) + assertTrue(simulationResult[1].transactionTrace is DeployAccountTransactionTrace) + + val invokeTxWithoutSignature = invokeTx.copy(signature = emptyList()) + val deployAccountTxWithoutSignature = deployAccountTx.copy(signature = emptyList()) + + val simulationFlags2 = setOf(SimulationFlag.SKIP_VALIDATE) + val simulationResult2 = provider.simulateTransactions( + transactions = listOf(invokeTxWithoutSignature, deployAccountTxWithoutSignature), + blockTag = BlockTag.PENDING, + simulationFlags = simulationFlags2, + ).send() - assertEquals(2, simulationResult2.size) - assertTrue(simulationResult[0].transactionTrace is InvokeTransactionTraceBase) - assertTrue(simulationResult[0].transactionTrace is InvokeTransactionTrace) - assertTrue(simulationResult[1].transactionTrace is DeployAccountTransactionTrace) - } + assertEquals(2, simulationResult2.size) + assertTrue(simulationResult[0].transactionTrace is InvokeTransactionTraceBase) + assertTrue(simulationResult[0].transactionTrace is InvokeTransactionTrace) + assertTrue(simulationResult[1].transactionTrace is DeployAccountTransactionTrace) + } - @Test - fun `simulate declare v1 transaction`() { - val contractCode = Path.of("src/test/resources/contracts_v0/target/release/balance.json").readText() - val contractDefinition = Cairo0ContractDefinition(contractCode) - val nonce = account.getNonce().send() + @Test + fun `simulate invoke v3 and deploy account v3 transactions`() { + val account = StandardAccount(accountAddress, signer, provider) + devnetClient.prefundAccountStrk(accountAddress) - // Note to future developers experiencing failures in this test. - // 1. Compiled contract format sometimes changes, this causes changes in the class hash. - // If this test starts randomly falling, try recalculating class hash. - // 2. If it fails on CI, make sure to delete the compiled contracts before running this test. - // Chances are, the contract was compiled with a different compiler version. - - val classHash = Felt.fromHex("0x6d5c6e633015a1cb4637233f181a9bb9599be26ff16a8ce335822b41f98f70b") - val declareTransactionPayload = account.signDeclare( - contractDefinition, - classHash, - ExecutionParams( + val nonce = account.getNonce().send() + val call = Call(balanceContractAddress, "increase_balance", listOf(Felt(1000))) + val params = InvokeParamsV3( nonce = nonce, - maxFee = Felt(1000000000000000L), - ), - ) - val simulationFlags = setOf() - val simulationResult = provider.simulateTransactions( - transactions = listOf(declareTransactionPayload), - blockTag = BlockTag.LATEST, - simulationFlags = simulationFlags, - ).send() - assertEquals(1, simulationResult.size) - val trace = simulationResult.first().transactionTrace - assertTrue(trace is DeclareTransactionTrace) - } + l1ResourceBounds = ResourceBounds( + maxAmount = Uint64(20000), + maxPricePerUnit = Uint128(120000000000), + ), + ) - @Test - fun `simulate declare v2 transaction`() { - 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"), - ) - val contractCode = Path.of("src/test/resources/contracts_v1/target/release/ContractsV1_SaltedHelloStarknet.sierra.json").readText() - val casmCode = Path.of("src/test/resources/contracts_v1/target/release/ContractsV1_SaltedHelloStarknet.casm.json").readText() + val invokeTx = account.signV3(call, params) - val contractDefinition = Cairo1ContractDefinition(contractCode) - val casmContractDefinition = CasmContractDefinition(casmCode) + val privateKey = Felt(22222) + val publicKey = StarknetCurve.getPublicKey(privateKey) + val salt = Felt.ONE + val calldata = listOf(publicKey) - val nonce = account.getNonce().send() - val declareTransactionPayload = account.signDeclare( - contractDefinition, - casmContractDefinition, - ExecutionParams( - nonce = nonce, - maxFee = Felt(1000000000000000L), - ), - ) + val newAccountAddress = ContractAddressCalculator.calculateAddressFromHash( + classHash = accountContractClassHash, + calldata = calldata, + salt = salt, + ) + val newAccount = StandardAccount(newAccountAddress, privateKey, provider) - val simulationFlags = setOf() - val simulationResult = provider.simulateTransactions( - transactions = listOf(declareTransactionPayload), - blockTag = BlockTag.LATEST, - simulationFlags = simulationFlags, - ).send() - assertEquals(1, simulationResult.size) - val trace = simulationResult.first().transactionTrace - assertTrue(trace is DeclareTransactionTrace) - } + devnetClient.prefundAccountStrk(newAccountAddress) + val deployAccountTx = newAccount.signDeployAccountV3( + classHash = accountContractClassHash, + salt = salt, + calldata = calldata, + l1ResourceBounds = ResourceBounds( + maxAmount = Uint64(20000), + maxPricePerUnit = Uint128(120000000000), + ), + ) - // TODO: replace this with a proper devnet test - // Legacy devnet never returns invoke transaction trace that has revert_reason field in execution_invocation. - @Test - fun `simulate reverted invoke transaction`() { - val mockedResponse = """ - { - "jsonrpc": "2.0", - "id": 0, - "result": [ - { - "fee_estimation": { - "gas_consumed": "0x9d8", - "gas_price": "0x3b9aca2f", - "overall_fee": "0x24abbb63ea8" - }, - "transaction_trace": { - "type": "INVOKE", - "execute_invocation": { - "revert_reason": "Placeholder revert reason." - } - } - } - ] + val simulationFlags = setOf() + val simulationResult = provider.simulateTransactions( + transactions = listOf(invokeTx, deployAccountTx), + blockTag = BlockTag.PENDING, + simulationFlags = simulationFlags, + ).send() + assertEquals(2, simulationResult.size) + assertTrue(simulationResult[0].transactionTrace is InvokeTransactionTraceBase) + assertTrue(simulationResult[0].transactionTrace is InvokeTransactionTrace) + assertTrue(simulationResult[1].transactionTrace is DeployAccountTransactionTrace) } - """.trimIndent() - val httpService = mock { - on { send(any()) } doReturn HttpResponse(true, 200, mockedResponse) + + @Test + fun `simulate declare v1 transaction`() { + val contractCode = Path.of("src/test/resources/contracts_v0/target/release/balance.json").readText() + val contractDefinition = Cairo0ContractDefinition(contractCode) + val nonce = account.getNonce().send() + + // Note to future developers experiencing failures in this test. + // 1. Compiled contract format sometimes changes, this causes changes in the class hash. + // If this test starts randomly falling, try recalculating class hash. + // 2. If it fails on CI, make sure to delete the compiled contracts before running this test. + // Chances are, the contract was compiled with a different compiler version. + + val classHash = Felt.fromHex("0x6d5c6e633015a1cb4637233f181a9bb9599be26ff16a8ce335822b41f98f70b") + val declareTransactionPayload = account.signDeclareV1( + contractDefinition, + classHash, + ExecutionParams( + nonce = nonce, + maxFee = Felt(1000000000000000L), + ), + ) + val simulationFlags = setOf() + val simulationResult = provider.simulateTransactions( + transactions = listOf(declareTransactionPayload), + blockTag = BlockTag.PENDING, + simulationFlags = simulationFlags, + ).send() + assertEquals(1, simulationResult.size) + val trace = simulationResult.first().transactionTrace + assertTrue(trace is DeclareTransactionTrace) } - val mockProvider = JsonRpcProvider(devnetClient.rpcUrl, httpService) - val nonce = account.getNonce().send() - val maxFee = Felt(1) - val call = Call(balanceContractAddress, "increase_balance", listOf(Felt(1000))) - val params = ExecutionParams(nonce, maxFee) - val invokeTx = account.sign(call, params) - - val simulationFlags = setOf() - val simulationResult = mockProvider.simulateTransactions( - transactions = listOf(invokeTx), - blockTag = BlockTag.LATEST, - simulationFlags = simulationFlags, - ).send() - - val trace = simulationResult.first().transactionTrace - assertTrue(trace is InvokeTransactionTraceBase) - assertTrue(trace is RevertedInvokeTransactionTrace) - val revertedTrace = trace as RevertedInvokeTransactionTrace - assertNotNull(revertedTrace.executeInvocation) - assertNotNull(revertedTrace.executeInvocation.revertReason) - } + @Test + fun `simulate declare v2 transaction`() { + 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"), + ) + val contractCode = + Path.of("src/test/resources/contracts_v1/target/release/ContractsV1_SaltedHelloStarknet.sierra.json") + .readText() + val casmCode = + Path.of("src/test/resources/contracts_v1/target/release/ContractsV1_SaltedHelloStarknet.casm.json") + .readText() - @Test - fun `simulate transaction with messages`() { - val mockedResponse = """ - { - "jsonrpc": "2.0", - "id": 0, - "result": [ - { - "fee_estimation": { - "gas_consumed": "0x9d8", - "gas_price": "0x3b9aca2f", - "overall_fee": "0x24abbb63ea8" - }, - "transaction_trace": { - "type": "INVOKE", - "execute_invocation": { - "contract_address": "0x4428a52af4b56b60eafba3bfe8d45f06b3ba6567db259e1f815f818632fd18f", - "entry_point_selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad", - "calldata": [ - "0x1", - "0x2" - ], - "caller_address": "0x0", - "class_hash": "0x4d07e40e93398ed3c76981e72dd1fd22557a78ce36c0515f679e27f0bb5bc5f", - "entry_point_type": "EXTERNAL", - "call_type": "CALL", - "result": [ - "0x1", - "0x1" - ], - "calls": [ - { - "contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", - "entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", - "calldata": [ - "0x1", - "0x3e8", - "0x0" - ], - "caller_address": "0x4428a52af4b56b60eafba3bfe8d45f06b3ba6567db259e1f815f818632fd18f", - "class_hash": "0x6a22bf63c7bc07effa39a25dfbd21523d211db0100a0afd054d172b81840eaf", - "entry_point_type": "EXTERNAL", - "call_type": "CALL", - "result": [ - "0x1" - ], - "calls": [], - "events": [ - { - "keys": [ - "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" - ], - "data": [ - "0x4428a52af4b56b60eafba3bfe8d45f06b3ba6567db259e1f815f818632fd18f", - "0x1" - ], - "order": 0 + val contractDefinition = Cairo1ContractDefinition(contractCode) + val casmContractDefinition = CasmContractDefinition(casmCode) + + val nonce = account.getNonce().send() + val declareTransactionPayload = account.signDeclareV2( + contractDefinition, + casmContractDefinition, + ExecutionParams( + nonce = nonce, + maxFee = Felt(1000000000000000L), + ), + ) + + val simulationFlags = setOf() + val simulationResult = provider.simulateTransactions( + transactions = listOf(declareTransactionPayload), + blockTag = BlockTag.PENDING, + simulationFlags = simulationFlags, + ).send() + assertEquals(1, simulationResult.size) + val trace = simulationResult.first().transactionTrace + assertTrue(trace is DeclareTransactionTrace) + } + + @Test + fun `simulate declare v3 transaction`() { + 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"), + ) + val contractCode = + Path.of("src/test/resources/contracts_v1/target/release/ContractsV1_SaltedHelloStarknet.sierra.json") + .readText() + val casmCode = + Path.of("src/test/resources/contracts_v1/target/release/ContractsV1_SaltedHelloStarknet.casm.json") + .readText() + + val contractDefinition = Cairo1ContractDefinition(contractCode) + val casmContractDefinition = CasmContractDefinition(casmCode) + + val nonce = account.getNonce().send() + val declareTransactionPayload = account.signDeclareV3( + contractDefinition, + casmContractDefinition, + DeclareParamsV3( + nonce = nonce, + l1ResourceBounds = ResourceBounds( + maxAmount = Uint64(20000), + maxPricePerUnit = Uint128(120000000000), + ), + ), + ) + + val simulationFlags = setOf() + val simulationResult = provider.simulateTransactions( + transactions = listOf(declareTransactionPayload), + blockTag = BlockTag.PENDING, + simulationFlags = simulationFlags, + ).send() + assertEquals(1, simulationResult.size) + val trace = simulationResult.first().transactionTrace + assertTrue(trace is DeclareTransactionTrace) + } + + // TODO: replace this with a proper devnet test + // Legacy devnet never returns invoke transaction trace that has revert_reason field in execution_invocation. + @Test + fun `simulate reverted invoke transaction`() { + val mockedResponse = """ + { + "jsonrpc": "2.0", + "id": 0, + "result": [ + { + "fee_estimation": { + "gas_consumed": "0x9d8", + "gas_price": "0x3b9aca2f", + "overall_fee": "0x24abbb63ea8" + }, + "transaction_trace": { + "type": "INVOKE", + "execute_invocation": { + "revert_reason": "Placeholder revert reason." + } + } + } + ] + } + """.trimIndent() + val httpService = mock { + on { send(any()) } doReturn HttpResponse(true, 200, mockedResponse) + } + val mockProvider = JsonRpcProvider(devnetClient.rpcUrl, httpService) + + val nonce = account.getNonce().send() + val maxFee = Felt(1) + val call = Call(balanceContractAddress, "increase_balance", listOf(Felt(1000))) + val params = ExecutionParams(nonce, maxFee) + val invokeTx = account.signV1(call, params) + + val simulationFlags = setOf() + val simulationResult = mockProvider.simulateTransactions( + transactions = listOf(invokeTx), + blockTag = BlockTag.PENDING, + simulationFlags = simulationFlags, + ).send() + + val trace = simulationResult.first().transactionTrace + assertTrue(trace is InvokeTransactionTraceBase) + assertTrue(trace is RevertedInvokeTransactionTrace) + val revertedTrace = trace as RevertedInvokeTransactionTrace + assertNotNull(revertedTrace.executeInvocation) + assertNotNull(revertedTrace.executeInvocation.revertReason) + } + + @Test + fun `simulate transaction with messages`() { + val mockedResponse = """ + { + "jsonrpc": "2.0", + "id": 0, + "result": [ + { + "fee_estimation": { + "gas_consumed": "0x9d8", + "gas_price": "0x3b9aca2f", + "overall_fee": "0x24abbb63ea8" + }, + "transaction_trace": { + "type": "INVOKE", + "execute_invocation": { + "contract_address": "0x4428a52af4b56b60eafba3bfe8d45f06b3ba6567db259e1f815f818632fd18f", + "entry_point_selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad", + "calldata": [ + "0x1", + "0x2" + ], + "caller_address": "0x0", + "class_hash": "0x4d07e40e93398ed3c76981e72dd1fd22557a78ce36c0515f679e27f0bb5bc5f", + "entry_point_type": "EXTERNAL", + "call_type": "CALL", + "result": [ + "0x1", + "0x1" + ], + "calls": [ + { + "contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", + "calldata": [ + "0x1", + "0x3e8", + "0x0" + ], + "caller_address": "0x4428a52af4b56b60eafba3bfe8d45f06b3ba6567db259e1f815f818632fd18f", + "class_hash": "0x6a22bf63c7bc07effa39a25dfbd21523d211db0100a0afd054d172b81840eaf", + "entry_point_type": "EXTERNAL", + "call_type": "CALL", + "result": [ + "0x1" + ], + "calls": [], + "events": [ + { + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x4428a52af4b56b60eafba3bfe8d45f06b3ba6567db259e1f815f818632fd18f", + "0x1" + ], + "order": 0 + } + ], + "messages": [], + "execution_resources": { + "steps": 582 } - ], - "messages": [], - "execution_resources": { - "steps": 582 } + ], + "events": [], + "messages": [ + { + "order": 0, + "from_address": "0x123", + "to_address": "0x456", + "payload": ["0x1", "0x2"] + }, + { + "order": 1, + "from_address": "0x456", + "to_address": "0x789", + "payload": [] + } + ], + "execution_resources": { + "steps": 800 } - ], - "events": [], - "messages": [ - { - "order": 0, - "from_address": "0x123", - "to_address": "0x456", - "payload": ["0x1", "0x2"] - }, - { - "order": 1, - "from_address": "0x456", - "to_address": "0x789", - "payload": [] - } - ], - "execution_resources": { - "steps": 800 } } } - } - ] - } - """.trimIndent() - val httpService = mock { - on { send(any()) } doReturn HttpResponse(true, 200, mockedResponse) - } - val mockProvider = JsonRpcProvider(devnetClient.rpcUrl, httpService) + ] + } + """.trimIndent() + val httpService = mock { + on { send(any()) } doReturn HttpResponse(true, 200, mockedResponse) + } + val mockProvider = JsonRpcProvider(devnetClient.rpcUrl, httpService) - val nonce = account.getNonce().send() - val maxFee = Felt(1) - val call = Call(balanceContractAddress, "increase_balance", listOf(Felt(1000))) - val params = ExecutionParams(nonce, maxFee) - val invokeTx = account.sign(call, params) - - val simulationFlags = setOf() - val simulationResult = mockProvider.simulateTransactions( - transactions = listOf(invokeTx), - blockTag = BlockTag.PENDING, - simulationFlags = simulationFlags, - ).send() - - val trace = simulationResult.first().transactionTrace - assertTrue(trace is InvokeTransactionTrace) - val invokeTrace = trace as InvokeTransactionTrace - val messages = invokeTrace.executeInvocation.messages - assertEquals(2, messages.size) - assertEquals(0, messages[0].order) - assertEquals(1, messages[1].order) + val nonce = account.getNonce().send() + val maxFee = Felt(1) + val call = Call(balanceContractAddress, "increase_balance", listOf(Felt(1000))) + val params = ExecutionParams(nonce, maxFee) + val invokeTx = account.signV1(call, params) + + val simulationFlags = setOf() + val simulationResult = mockProvider.simulateTransactions( + transactions = listOf(invokeTx), + blockTag = BlockTag.PENDING, + simulationFlags = simulationFlags, + ).send() + + val trace = simulationResult.first().transactionTrace + assertTrue(trace is InvokeTransactionTrace) + val invokeTrace = trace as InvokeTransactionTrace + val messages = invokeTrace.executeInvocation.messages + assertEquals(2, messages.size) + assertEquals(0, messages[0].order) + assertEquals(1, messages[1].order) + } } } diff --git a/lib/src/test/kotlin/starknet/crypto/FeeUtilsTest.kt b/lib/src/test/kotlin/starknet/crypto/FeeUtilsTest.kt index 41faa54b5..e802d8d8b 100644 --- a/lib/src/test/kotlin/starknet/crypto/FeeUtilsTest.kt +++ b/lib/src/test/kotlin/starknet/crypto/FeeUtilsTest.kt @@ -46,7 +46,6 @@ class FeeUtilsTest { val result = estimateFee.toResourceBounds() val expected = ResourceBoundsMapping( l1Gas = ResourceBounds(maxAmount = Uint64(1100), maxPricePerUnit = Uint128(150)), - l2Gas = ResourceBounds(maxAmount = Uint64.ZERO, maxPricePerUnit = Uint128.ZERO), ) assertEquals(expected, result) } @@ -56,7 +55,6 @@ class FeeUtilsTest { val result = estimateFee.toResourceBounds(0.19, 0.13) val expected = ResourceBoundsMapping( l1Gas = ResourceBounds(maxAmount = Uint64(1190), maxPricePerUnit = Uint128(113)), - l2Gas = ResourceBounds(maxAmount = Uint64.ZERO, maxPricePerUnit = Uint128.ZERO), ) assertEquals(expected, result) } @@ -66,7 +64,6 @@ class FeeUtilsTest { val result = estimateFee.toResourceBounds(0.0, 0.0) val expected = ResourceBoundsMapping( l1Gas = ResourceBounds(maxAmount = Uint64(1000), maxPricePerUnit = Uint128(100)), - l2Gas = ResourceBounds(maxAmount = Uint64.ZERO, maxPricePerUnit = Uint128.ZERO), ) assertEquals(expected, result) } diff --git a/lib/src/test/kotlin/starknet/deployercontract/StandardDeployerTest.kt b/lib/src/test/kotlin/starknet/deployercontract/StandardDeployerTest.kt index 53386edac..9fa7cd793 100644 --- a/lib/src/test/kotlin/starknet/deployercontract/StandardDeployerTest.kt +++ b/lib/src/test/kotlin/starknet/deployercontract/StandardDeployerTest.kt @@ -1,11 +1,8 @@ package starknet.deployercontract import com.swmansion.starknet.account.StandardAccount -import com.swmansion.starknet.data.types.BlockTag -import com.swmansion.starknet.data.types.Call -import com.swmansion.starknet.data.types.Felt +import com.swmansion.starknet.data.types.* import com.swmansion.starknet.deployercontract.StandardDeployer -import com.swmansion.starknet.provider.Provider import com.swmansion.starknet.provider.rpc.JsonRpcProvider import com.swmansion.starknet.signer.Signer import com.swmansion.starknet.signer.StarkCurveSigner @@ -55,89 +52,120 @@ object StandardDeployerTest { } } - data class StandardDeployerParameters( - val standardDeployer: StandardDeployer, - val provider: Provider, - val addressBook: AddressBook, - ) - data class AddressBook( - val deployerAddress: Felt, - val accountAddress: Felt, - val balanceContractClassHash: Felt, - ) + @Test + fun `test udc deploy v1`() { + val initialBalance = Felt(1000) + val deployment = standardDeployer.deployContractV1( + classHash = balanceContractClassHash, + unique = true, + salt = Felt(101), + constructorCalldata = listOf(initialBalance), + ).send() + val address = standardDeployer.findContractAddress(deployment).send() + + val contractValue = provider.callContract(Call(address, "get_balance")).send() + assertEquals(listOf(initialBalance), contractValue) + } @Test - fun `test udc deploy`() { + fun `test udc deploy v3`() { val initialBalance = Felt(1000) - val deployment = standardDeployer.deployContract( + val deployment = standardDeployer.deployContractV3( classHash = balanceContractClassHash, unique = true, - salt = Felt(1234), + salt = Felt(301), constructorCalldata = listOf(initialBalance), ).send() val address = standardDeployer.findContractAddress(deployment).send() - assertDoesNotThrow { provider.callContract(Call(address, "get_balance"), BlockTag.LATEST).send() } + val contractValue = provider.callContract(Call(address, "get_balance")).send() + assertEquals(listOf(initialBalance), contractValue) } @Test - fun `test udc deploy with specific fee`() { + fun `test udc deploy v1 with specific fee`() { val initialBalance = Felt(1000) - val deployment = standardDeployer.deployContract( + val deployment = standardDeployer.deployContractV1( classHash = balanceContractClassHash, unique = true, - salt = Felt(789), + salt = Felt(102), constructorCalldata = listOf(initialBalance), maxFee = Felt(1_000_000_000_000_000), ).send() val address = standardDeployer.findContractAddress(deployment).send() - assertDoesNotThrow { provider.callContract(Call(address, "get_balance"), BlockTag.LATEST).send() } + val contractValue = provider.callContract(Call(address, "get_balance")).send() + assertEquals(listOf(initialBalance), contractValue) } @Test - fun `test udc deploy with default parameters`() { + fun `test udc deploy v3 with specific resource bounds`() { val initialBalance = Felt(1000) - val deployment = standardDeployer.deployContract( + val deployment = standardDeployer.deployContractV3( classHash = balanceContractClassHash, + unique = true, + salt = Felt(302), constructorCalldata = listOf(initialBalance), + l1ResourceBounds = ResourceBounds( + maxAmount = Uint64(50000), + maxPricePerUnit = Uint128(100_000_000_000), + ), ).send() val address = standardDeployer.findContractAddress(deployment).send() - assertDoesNotThrow { provider.callContract(Call(address, "get_balance"), BlockTag.LATEST).send() } - } + val contractValue = provider.callContract(Call(address, "get_balance")).send() + assertEquals(listOf(initialBalance), contractValue) } @Test - fun `test udc deploy with specific fee and default parameters`() { + fun `test udc deploy v1 with default parameters`() { val initialBalance = Felt(1000) - val deployment = standardDeployer.deployContract( + val deployment = standardDeployer.deployContractV1( classHash = balanceContractClassHash, constructorCalldata = listOf(initialBalance), - maxFee = Felt(1_000_000_000_000_000), ).send() val address = standardDeployer.findContractAddress(deployment).send() - assertDoesNotThrow { provider.callContract(Call(address, "get_balance"), BlockTag.LATEST).send() } - } + val contractValue = provider.callContract(Call(address, "get_balance")).send() + assertEquals(listOf(initialBalance), contractValue) } + + @Test + fun `test udc deploy v3 with default parameters`() { + val initialBalance = Felt(1000) + val deployment = standardDeployer.deployContractV3( + classHash = balanceContractClassHash, + constructorCalldata = listOf(initialBalance), + ).send() + val address = standardDeployer.findContractAddress(deployment).send() + + val contractValue = provider.callContract(Call(address, "get_balance")).send() + assertEquals(listOf(initialBalance), contractValue) } @Test - fun `test udc deploy with constructor`() { - val classHash = devnetClient.declareContract("ContractWithConstructor").classHash - val constructorVal1 = Felt(451) + fun `test udc deploy v1 with specific fee and default parameters`() { + val initialBalance = Felt(1000) + val deployment = standardDeployer.deployContractV1( + classHash = balanceContractClassHash, + constructorCalldata = listOf(initialBalance), + maxFee = Felt(1_000_000_000_000_000), + ).send() + val address = standardDeployer.findContractAddress(deployment).send() - val deployment = standardDeployer.deployContract( - classHash = classHash, - unique = true, - salt = Felt(1234), - constructorCalldata = listOf( - constructorVal1, - Felt(789), // Dummy value, ignored by the contract constructor. + val contractValue = provider.callContract(Call(address, "get_balance")).send() + assertEquals(listOf(initialBalance), contractValue) } + + @Test + fun `test udc deploy v3 with specific fee and default parameters`() { + val initialBalance = Felt(1000) + val deployment = standardDeployer.deployContractV3( + classHash = balanceContractClassHash, + constructorCalldata = listOf(initialBalance), + l1ResourceBounds = ResourceBounds( + maxAmount = Uint64(50000), + maxPricePerUnit = Uint128(100_000_000_000), ), ).send() val address = standardDeployer.findContractAddress(deployment).send() - val contractValue = provider.callContract(Call(address, "get_val1"), BlockTag.LATEST).send() - - assertEquals(listOf(constructorVal1), contractValue) - } + val contractValue = provider.callContract(Call(address, "get_balance")).send() + assertEquals(listOf(initialBalance), contractValue) } } diff --git a/lib/src/test/kotlin/starknet/provider/response/JsonRpcResponseTest.kt b/lib/src/test/kotlin/starknet/provider/response/JsonRpcResponseTest.kt index 72884a1f6..769b8a864 100644 --- a/lib/src/test/kotlin/starknet/provider/response/JsonRpcResponseTest.kt +++ b/lib/src/test/kotlin/starknet/provider/response/JsonRpcResponseTest.kt @@ -75,7 +75,7 @@ class JsonRpcResponseTest { } @Test - fun `rpc provider parses rpc error`() { + fun `rpc provider parses rpc error without data`() { val message = """ { "id": 0, @@ -100,16 +100,20 @@ class JsonRpcResponseTest { } @Test - fun `rpc provider parses rpc contract error`() { + fun `rpc provider parses rpc error with data object`() { val message = """ { "id": 0, "jsonrpc": "2.0", "error": { - "code": 40, - "message": "Contract error", + "code": -32603, + "message": "Internal error", "data": { - "revert_error": "Example revert error" + "error": "Invalid message selector", + "details": { + "selector": "0x1234", + "id": 789 + } } } } @@ -123,13 +127,13 @@ class JsonRpcResponseTest { val exception = assertThrows(RpcRequestFailedException::class.java) { request.send() } - assertEquals(40, exception.code) - assertEquals("Contract error", exception.message) - assertEquals("Example revert error", exception.data) + assertEquals(-32603, exception.code) + assertEquals("Internal error", exception.message) + assertEquals("{\"error\":\"Invalid message selector\",\"details\":{\"selector\":\"0x1234\",\"id\":789}}", exception.data) } @Test - fun `rpc provider parses rpc error with data object`() { + fun `rpc provider parses rpc error with data primitive`() { val message = """ { "id": 0, @@ -137,12 +141,7 @@ class JsonRpcResponseTest { "error": { "code": -32603, "message": "Internal error", - "data": { - "error": "Invalid message selector", - "details": { - "selector": "0x1234" - } - } + "data": "Invalid message selector" } } """.trimIndent() @@ -157,11 +156,11 @@ class JsonRpcResponseTest { } assertEquals(-32603, exception.code) assertEquals("Internal error", exception.message) - assertEquals("{\"error\":\"Invalid message selector\",\"details\":{\"selector\":\"0x1234\"}}", exception.data) + assertEquals("Invalid message selector", exception.data) } @Test - fun `rpc provider parses rpc error with data primitive`() { + fun `rpc handler parses rpc error with data array`() { val message = """ { "id": 0, @@ -169,7 +168,10 @@ class JsonRpcResponseTest { "error": { "code": -32603, "message": "Internal error", - "data": "Invalid message selector" + "data": [ + "Invalid message selector", + "0x1234" + ] } } """.trimIndent() @@ -184,6 +186,6 @@ class JsonRpcResponseTest { } assertEquals(-32603, exception.code) assertEquals("Internal error", exception.message) - assertEquals("Invalid message selector", exception.data) + assertEquals("[\"Invalid message selector\",\"0x1234\"]", exception.data) } } diff --git a/lib/src/test/resources/contracts/src/contract_with_constructor.cairo b/lib/src/test/resources/contracts/src/contract_with_constructor.cairo deleted file mode 100644 index 261a50f26..000000000 --- a/lib/src/test/resources/contracts/src/contract_with_constructor.cairo +++ /dev/null @@ -1,28 +0,0 @@ -#[starknet::interface] -trait IContractWithConstructor { - // Returns the current val1. - fn get_val1(self: @T) -> u128; -} - -#[starknet::contract] -mod ContractWithConstructor { - use traits::Into; - - #[storage] - struct Storage { - val1: u128, - } - - #[constructor] - fn constructor(ref self: ContractState, val1_: u128, val2_: u128) { - self.val1.write(val1_); - // val2_ is not used. - } - - #[external(v0)] - impl ContractWithConstructor of super::IContractWithConstructor { - fn get_val1(self: @ContractState) -> u128 { - self.val1.read() - } - } -} diff --git a/lib/src/test/resources/contracts/src/lib.cairo b/lib/src/test/resources/contracts/src/lib.cairo index 761b4ba9a..049c76fe5 100644 --- a/lib/src/test/resources/contracts/src/lib.cairo +++ b/lib/src/test/resources/contracts/src/lib.cairo @@ -1,4 +1,3 @@ mod balance; -mod contract_with_constructor; mod events; mod map; diff --git a/lib/src/test/resources/contracts_v2/src/salted_counter_contract.cairo b/lib/src/test/resources/contracts_v2/src/salted_counter_contract.cairo index e69de29bb..8b1378917 100644 --- a/lib/src/test/resources/contracts_v2/src/salted_counter_contract.cairo +++ b/lib/src/test/resources/contracts_v2/src/salted_counter_contract.cairo @@ -0,0 +1 @@ + diff --git a/test_variables.env.example b/test_variables.env.example index 1c527a3a9..a8b773275 100644 --- a/test_variables.env.example +++ b/test_variables.env.example @@ -4,7 +4,7 @@ DEVNET_PATH=/path/to/starknet-devnet-rs/target/release/starknet-devnet NETWORK_TEST_MODE=disabled NETWORK_TEST_NETWORK_NAME=GOERLI_INTEGRATION -# Goerli Integration tests +# Goerli Integration config GOERLI_INTEGRATION_RPC_URL=http://example-node-url.com/rpc GOERLI_INTEGRATION_PRIVATE_KEY=0x123456789 GOERLI_INTEGRATION_ACCOUNT_ADDRESS=0x123456789123456789123456789123456789123456789123456789123456789 @@ -20,7 +20,7 @@ GOERLI_TESTNET_CONST_NONCE_PRIVATE_KEY=0x1a1a1a1a1a GOERLI_TESTNET_CONST_NONCE_ACCOUNT_ADDRESS=0x2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2 GOERLI_TESTNET_ACCOUNT_CAIRO_VERSION=0 -# Sepolia Integration tests +# Sepolia Integration config SEPOLIA_INTEGRATION_RPC_URL=http://example-node-url.com/rpc SEPOLIA_INTEGRATION_PRIVATE_KEY=0x123456789 SEPOLIA_INTEGRATION_ACCOUNT_ADDRESS=0x123456789123456789123456789123456789123456789123456789123456789