diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 2ee6eb867..356d5a37e 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -16,7 +16,7 @@ jobs: runs-on: ${{ matrix.os }} env: - DEVNET_SHA: 85495efb71a37ad3921c8986474b7e78a9a9f5fc + DEVNET_SHA: 1bd447d8ac8c2fb0a3eaf2d54512671f4a16c7ba steps: - uses: actions/checkout@v3 with: @@ -91,14 +91,14 @@ jobs: DEVNET_PATH: ${{ github.workspace }}/starknet-devnet-rs/target/release/starknet-devnet NETWORK_TEST_MODE: "disabled" NETWORK_TEST_NETWORK_NAME: "TESTNET" - TESTNET_RPC_URL: ${{ secrets.TESTNET_RPC_URL }} - TESTNET_ACCOUNT_ADDRESS: ${{ secrets.TESTNET_ACCOUNT_ADDRESS }} - TESTNET_PRIVATE_KEY: ${{ secrets.TESTNET_PRIVATE_KEY }} - TESTNET_CONST_NONCE_ACCOUNT_ADDRESS: ${{ secrets.TESTNET_CONST_NONCE_ACCOUNT_ADDRESS }} - TESTNET_CONST_NONCE_PRIVATE_KEY: ${{ secrets.TESTNET_CONST_NONCE_PRIVATE_KEY }} + GOERLI_TESTNET_RPC_URL: ${{ secrets.TESTNET_RPC_URL }} + GOERLI_TESTNET_ACCOUNT_ADDRESS: ${{ secrets.TESTNET_ACCOUNT_ADDRESS }} + GOERLI_TESTNET_PRIVATE_KEY: ${{ secrets.TESTNET_PRIVATE_KEY }} + GOERLI_TESTNET_CONST_NONCE_ACCOUNT_ADDRESS: ${{ secrets.TESTNET_CONST_NONCE_ACCOUNT_ADDRESS }} + GOERLI_TESTNET_CONST_NONCE_PRIVATE_KEY: ${{ secrets.TESTNET_CONST_NONCE_PRIVATE_KEY }} run: ./gradlew :lib:koverXmlReport --info - name: Upload coverage to Codecov uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 with: - files: lib/build/reports/kover/project-xml/report.xml + files: lib/build/reports/kover/report.xml diff --git a/README.md b/README.md index 73f6c4ca0..065ac9361 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ import com.swmansion.starknet.provider.rpc.JsonRpcProvider; public class Main { public static void main(String[] args) { // Create a provider for interacting with Starknet - Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET); + Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc"); // Create an account interface Felt accountAddress = Felt.fromHex("0x13241455"); @@ -93,7 +93,7 @@ import java.util.concurrent.CompletableFuture; public class Main { public static void main(String[] args) { // Create a provider for interacting with Starknet - Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET); + Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc"); // Create an account interface Felt accountAddress = Felt.fromHex("0x13241455"); @@ -133,16 +133,16 @@ This way you reuse connections and thread pools. ✅ **Do:** ```java -var provider = new JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET); +var provider = new JsonRpcProvider("https://example-node-url.com/rpc"); var account1 = new StandardAccount(provider, accountAddress1, privateKey1); var account2 = new StandardAccount(provider, accountAddress2, privateKey2); ``` ❌ **Don't:** ```java -var provider1 = new JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET); +var provider1 = new JsonRpcProvider("https://example-node-url.com/rpc"); var account1 = new StandardAccount(provider1, accountAddress1, privateKey1); -var provider2 = new JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET); +var provider2 = new JsonRpcProvider("https://example-node-url.com/rpc"); var account2 = new StandardAccount(provider2, accountAddress2, privateKey2); ``` @@ -180,10 +180,25 @@ Use the following command to run tests: ``` ### Network Tests -Running tests on networks (integration or testnet) requires a valid configuration. It can be set using environment variables in your system or IDE, or by sourcing an `.env` file. +Running tests on networks requires a valid configuration. It can be set using environment variables in your system or IDE, or by sourcing an `.env` file. Refer to the example config found in [test_variables.env.example](test_variables.env.example). -To select the network, please set the `NETWORK_TEST_NETWORK_NAME` environment variable. Currenty, the allowed options are `INTEGRATION` and `TESTNET`. -You will also need to provide an **RPC node URL** and an **account address** (along with its **private key**). +To select the network, please set the `NETWORK_TEST_NETWORK_NAME` environment variable. Currenty, the allowed options are: + - `SEPOLIA_TESTNET` + - `SEPOLIA_INTEGRATION` + - `GOERLI_TESTNET` + - `GOERLI_INTEGRATION` + +Please note that `GOERLI` networks are deprecated, and won't be supported in the future. The number of tests working on `SEPOLIA` is, however, temporarily limited. +To properly configure your network, ensure the following variables are set with the `NETWORK_NAME_` prefix: + - `RPC_URL` - url of your RPC node + - `ACCOUNT_ADDRESS` and `PRIVATE_KEY` - address and private key of your account + +Additionally, you can also set: + - `CONST_NONCE_ACCOUNT_ADDRESS` and `CONST_NONCE_PRIVATE_KEY` - address and private key exclusively for non-gas network tests, preventing potential inconsistencies (sometimes, `getNonce` may report higher nonce than expected). + Recommended for reliable non-gas testing. + These default to `ACCOUNT_ADDRESS` and `PRIVATE_KEY` if not set. + - `ACCOUNT_CAIRO_VERSION` - Cairo version of the `ACCOUNT_ADDRESS` and `CONST_NONCE_ACCOUNT_ADDRESS` accounts. Defaults to `0`. + Network tests are disabled by default. To enable them, you can set the environment variable: ```env NETWORK_TEST_MODE=non_gas @@ -199,12 +214,7 @@ Alternatively, you can use flag to specify whether to run network and gas tests: ./gradlew :lib:test -PnetworkTestMode=non_gas ./gradlew :lib:test -PnetworkTestMode=all ``` -Flag takes precendece over the env variable if both are set. - -⚠️ WARNING ⚠️ Some network tests may fail due to `getNonce` receiving higher nonce than expected by other methods. -It is adviced to additionaly provide an account (along with its **private key**) with a constant **nonce** to ensure non-gas tests pass. -Such account shouldn't be used for any other purpose than running non-gas network tests. -If not set, the main account provided in the config will be used for this purpose. +Flag takes precendece over the environment variable if both are set. ### Ensuring idiomatic Java code We want this library to be used by both kotlin & java users. In order to ensure a nice API for java always follow those rules: diff --git a/androiddemo/README.md b/androiddemo/README.md index c42d98682..9c227ac0f 100644 --- a/androiddemo/README.md +++ b/androiddemo/README.md @@ -44,7 +44,7 @@ Running the demo on a network other than devnet (Mainnet/Testen/Integration) req ### Prerequisites - Android emulator (Android Studio, IntelliJ IDEA, etc.) - URL of a Starknet RPC node. -- Account deployed on said network with some funds on it. If you're using **testnet**, you can obtain some funds from the [faucet](https://faucet.goerli.starknet.io/). +- Account deployed on said network with some funds on it. If you're using **Goerli testnet**, you can obtain some funds from the [faucet](https://faucet.goerli.starknet.io/). - A valid configuration that consists of the data above: - `DEMO_RPC_URL` - RPC node URL - `DEMO_ACCOUNT_ADDRESS` - account address diff --git a/androiddemo/src/main/java/com/example/androiddemo/MainActivity.kt b/androiddemo/src/main/java/com/example/androiddemo/MainActivity.kt index dc7de1783..2ddbe9fb7 100644 --- a/androiddemo/src/main/java/com/example/androiddemo/MainActivity.kt +++ b/androiddemo/src/main/java/com/example/androiddemo/MainActivity.kt @@ -132,7 +132,7 @@ class MainActivity : AppCompatActivity() { // Display the receipt details in the UI withContext(Dispatchers.Main) { receiptExecutionStatusValue.text = receipt.executionStatus.toString() - receiptActualFeeValue.text = receipt.actualFee?.let { "${it.value} wei" } ?: getString(R.string.not_available) + receiptActualFeeValue.text = receipt.actualFee.let { "${it.amount.value} ${it.unit.toString().lowercase()}" } receiptRevertReasonValue.text = receipt.revertReason ?: getString(R.string.not_available) } } catch (e: RpcRequestFailedException) { diff --git a/javademo/README.md b/javademo/README.md index d34698aa3..0d9d4f239 100644 --- a/javademo/README.md +++ b/javademo/README.md @@ -48,7 +48,7 @@ Running the demo on a network other than devnet (Mainnet/Testen/Integration) req ### Prerequisites - URL of a Starknet RPC node. - Details (address and private key) of an account deployed on said network with some funds on it. -If you're using **testnet**, you can obtain some funds from the [faucet](https://faucet.goerli.starknet.io/). +If you're using **Goerli testnet**, you can obtain some funds from the [faucet](https://faucet.goerli.starknet.io/). - [`asdf`](https://github.com/asdf-vm/asdf) version manager with [`asdf scarb`](https://github.com/software-mansion/asdf-scarb) plugin ### Steps diff --git a/javademo/src/main/java/com/example/javademo/Main.java b/javademo/src/main/java/com/example/javademo/Main.java index 993878d49..37fbd5a2a 100644 --- a/javademo/src/main/java/com/example/javademo/Main.java +++ b/javademo/src/main/java/com/example/javademo/Main.java @@ -8,6 +8,7 @@ import com.swmansion.starknet.data.types.transactions.DeclareTransactionV2Payload; import com.swmansion.starknet.data.types.transactions.TransactionReceipt; import com.swmansion.starknet.deployercontract.ContractDeployment; +import com.swmansion.starknet.deployercontract.Deployer; import com.swmansion.starknet.deployercontract.StandardDeployer; import com.swmansion.starknet.provider.Provider; import com.swmansion.starknet.provider.Request; @@ -37,7 +38,7 @@ private static class DemoConfig { public static void main(String[] args) throws Exception { // Create a provider for interacting with Starknet - JsonRpcProvider provider = new JsonRpcProvider(DemoConfig.rpcNodeUrl, StarknetChainId.TESTNET); + Provider provider = new JsonRpcProvider(DemoConfig.rpcNodeUrl, StarknetChainId.TESTNET); // Set up an account // Please note the account must be deployed and have enough funds to paying the fees @@ -167,7 +168,7 @@ private static DeployContractResult deployContract(Account account, Provider pro Felt salt = new Felt(20); // Deploy a contract - StandardDeployer contractDeployer = new StandardDeployer(udcAddress, provider, account); + Deployer contractDeployer = new StandardDeployer(udcAddress, provider, account); Request deployRequest = contractDeployer.deployContract(classHash, true, salt, constructorCalldata); ContractDeployment deployResponse = deployRequest.send(); 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 55fae73a9..fa2d9e556 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/account/StandardAccount.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/account/StandardAccount.kt @@ -27,6 +27,7 @@ class StandardAccount( private val provider: Provider, private val cairoVersion: Felt = Felt.ZERO, ) : Account { + private val chainId: StarknetChainId by lazy { provider.getChainId().send() } private fun estimateVersion(version: Felt): Felt { return BigInteger.valueOf(2).pow(128) .add(version.value) @@ -57,7 +58,7 @@ class StandardAccount( val tx = TransactionFactory.makeInvokeV1Transaction( senderAddress = address, calldata = calldata, - chainId = provider.chainId, + chainId = chainId, nonce = params.nonce, maxFee = params.maxFee, version = signVersion, @@ -77,7 +78,7 @@ class StandardAccount( val tx = TransactionFactory.makeInvokeV3Transaction( senderAddress = address, calldata = calldata, - chainId = provider.chainId, + chainId = chainId, nonce = params.nonce, version = signVersion, resourceBounds = params.resourceBounds, @@ -110,7 +111,7 @@ class StandardAccount( contractAddress = address, salt = salt, calldata = calldata, - chainId = provider.chainId, + chainId = chainId, maxFee = maxFee, version = signVersion, nonce = nonce, @@ -136,7 +137,7 @@ class StandardAccount( senderAddress = address, salt = salt, calldata = calldata, - chainId = provider.chainId, + chainId = chainId, version = signVersion, nonce = params.nonce, resourceBounds = params.resourceBounds, @@ -164,7 +165,7 @@ class StandardAccount( contractDefinition = contractDefinition, classHash = classHash, senderAddress = address, - chainId = provider.chainId, + chainId = chainId, nonce = params.nonce, maxFee = params.maxFee, version = signVersion, @@ -187,7 +188,7 @@ class StandardAccount( val tx = TransactionFactory.makeDeclareV2Transaction( contractDefinition = sierraContractDefinition, senderAddress = address, - chainId = provider.chainId, + chainId = chainId, nonce = params.nonce, maxFee = params.maxFee, version = signVersion, @@ -211,7 +212,7 @@ class StandardAccount( val tx = TransactionFactory.makeDeclareV3Transaction( contractDefinition = sierraContractDefinition, senderAddress = address, - chainId = provider.chainId, + chainId = chainId, nonce = params.nonce, version = signVersion, resourceBounds = params.resourceBounds, @@ -433,7 +434,7 @@ class StandardAccount( val signedTransaction = TransactionFactory.makeInvokeV1Transaction( senderAddress = payload.senderAddress, calldata = payload.calldata, - chainId = provider.chainId, + chainId = chainId, nonce = nonce, maxFee = payload.maxFee, signature = payload.signature, @@ -452,7 +453,7 @@ class StandardAccount( val signedTransaction = TransactionFactory.makeInvokeV3Transaction( senderAddress = payload.senderAddress, calldata = payload.calldata, - chainId = provider.chainId, + chainId = chainId, nonce = nonce, signature = payload.signature, version = payload.version, diff --git a/lib/src/main/kotlin/com/swmansion/starknet/data/types/Execution.kt b/lib/src/main/kotlin/com/swmansion/starknet/data/types/Execution.kt index 1e1d25bfb..c1e57d3e1 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/data/types/Execution.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/data/types/Execution.kt @@ -4,6 +4,7 @@ package com.swmansion.starknet.data.types import com.swmansion.starknet.data.selectorFromName import com.swmansion.starknet.data.types.conversions.ConvertibleToCalldata +import com.swmansion.starknet.extensions.toCalldata import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -64,7 +65,7 @@ data class Call( */ @JvmStatic fun fromCallArguments(contractAddress: Felt, entrypoint: Felt, arguments: CallArguments): Call { - val calldata = arguments.flatMap { it.toCalldata() } + val calldata = arguments.toCalldata() return Call(contractAddress, entrypoint, calldata) } diff --git a/lib/src/main/kotlin/com/swmansion/starknet/data/types/FeltArray.kt b/lib/src/main/kotlin/com/swmansion/starknet/data/types/FeltArray.kt new file mode 100644 index 000000000..401c7c248 --- /dev/null +++ b/lib/src/main/kotlin/com/swmansion/starknet/data/types/FeltArray.kt @@ -0,0 +1,11 @@ +package com.swmansion.starknet.data.types + +import com.swmansion.starknet.data.types.conversions.ConvertibleToCalldata + +data class FeltArray(private val list: MutableList) : ConvertibleToCalldata, MutableList by list { + constructor(vararg elements: Felt) : this(elements.toMutableList()) + constructor(collection: Collection) : this(collection.toMutableList()) + constructor() : this(emptyList()) + + override fun toCalldata(): List = list.toList() +} diff --git a/lib/src/main/kotlin/com/swmansion/starknet/data/types/StarknetChainId.kt b/lib/src/main/kotlin/com/swmansion/starknet/data/types/StarknetChainId.kt index bbe77066b..1bb8a068a 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/data/types/StarknetChainId.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/data/types/StarknetChainId.kt @@ -1,6 +1,20 @@ package com.swmansion.starknet.data.types +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable enum class StarknetChainId(val value: Felt) { + @SerialName("0x534e5f4d41494e") MAINNET(Felt.fromHex("0x534e5f4d41494e")), // encodeShortString('SN_MAIN'), - TESTNET(Felt.fromHex("0x534e5f474f45524c49")), // encodeShortString('SN_GOERLI'), + + @Deprecated("Consider using SEPOLIA instead") + @SerialName("0x534e5f474f45524c49") + GOERLI(Felt.fromHex("0x534e5f474f45524c49")), // encodeShortString('SN_GOERLI'), + + @SerialName("0x534e5f5345504f4c4941") + SEPOLIA_TESTNET(Felt.fromHex("0x534e5f5345504f4c4941")), // encodeShortString('SN_SEPOLIA'),] + + @SerialName("0x534e5f494e544547524154494f4e5f5345504f4c4941") + SEPOLIA_INTEGRATION(Felt.fromHex("0x534e5f494e544547524154494f4e5f5345504f4c4941")), // encodeShortString('SN_INTEGRATION_SEPOLIA'), } diff --git a/lib/src/main/kotlin/com/swmansion/starknet/extensions/ToCalldata.kt b/lib/src/main/kotlin/com/swmansion/starknet/extensions/ToCalldata.kt new file mode 100644 index 000000000..d0298ebbc --- /dev/null +++ b/lib/src/main/kotlin/com/swmansion/starknet/extensions/ToCalldata.kt @@ -0,0 +1,8 @@ +package com.swmansion.starknet.extensions + +import com.swmansion.starknet.data.types.Felt +import com.swmansion.starknet.data.types.conversions.ConvertibleToCalldata + +fun List.toCalldata(): List { + return this.flatMap { it.toCalldata() } +} 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 aacfb2b17..f0ab22625 100644 --- a/lib/src/main/kotlin/com/swmansion/starknet/provider/Provider.kt +++ b/lib/src/main/kotlin/com/swmansion/starknet/provider/Provider.kt @@ -10,8 +10,6 @@ import com.swmansion.starknet.provider.exceptions.RequestFailedException * Implementers of this interface provide methods for interacting with Starknet, for example through Starknet JSON-RPC. */ interface Provider { - val chainId: StarknetChainId - /** * Get a transaction. * @@ -632,6 +630,15 @@ interface Provider { */ fun getSyncing(): Request + /** + * Get the chain id. + * + * Get the currently configured Starknet chain id. + * + * @throws RequestFailedException + */ + fun getChainId(): Request + /** * Get a block with transactions. * 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 95eb473e4..ddad9e643 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 @@ -22,15 +22,13 @@ import kotlinx.serialization.json.* * httpService or provide it with your own httpService. * * @param url url of the service providing a rpc interface - * @param chainId an id of the network * @param httpService service used for making http requests */ class JsonRpcProvider( val url: String, - override val chainId: StarknetChainId, private val httpService: HttpService, ) : Provider { - constructor(url: String, chainId: StarknetChainId) : this(url, chainId, OkHttpService()) + constructor(url: String) : this(url, OkHttpService()) private val jsonWithDefaults = Json { encodeDefaults = true } @@ -482,6 +480,12 @@ class JsonRpcProvider( ) } + override fun getChainId(): Request { + val params = Json.encodeToJsonElement(JsonArray(emptyList())) + + return buildRequest(JsonRpcMethod.GET_CHAIN_ID, params, StarknetChainId.serializer()) + } + private fun getBlockWithTxs(payload: GetBlockWithTransactionsPayload): Request { val jsonPayload = Json.encodeToJsonElement(payload) @@ -620,6 +624,7 @@ private enum class JsonRpcMethod(val methodName: String) { GET_BLOCK_HASH_AND_NUMBER("starknet_blockHashAndNumber"), GET_BLOCK_TRANSACTION_COUNT("starknet_getBlockTransactionCount"), GET_SYNCING("starknet_syncing"), + GET_CHAIN_ID("starknet_chainId"), ESTIMATE_FEE("starknet_estimateFee"), ESTIMATE_MESSAGE_FEE("starknet_estimateMessageFee"), GET_BLOCK_WITH_TXS("starknet_getBlockWithTxs"), 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 bae81532e..78d4dac18 100644 --- a/lib/src/test/kotlin/com/swmansion/starknet/data/TransactionHashCalculatorTest.kt +++ b/lib/src/test/kotlin/com/swmansion/starknet/data/TransactionHashCalculatorTest.kt @@ -8,7 +8,7 @@ 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.TESTNET + private val chainId = StarknetChainId.GOERLI private val version = Felt.ONE @Test 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 index 317c2e7de..ca15e1b4d 100644 --- a/lib/src/test/kotlin/com/swmansion/starknet/data/types/FeltTest.kt +++ b/lib/src/test/kotlin/com/swmansion/starknet/data/types/FeltTest.kt @@ -1,5 +1,8 @@ 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 @@ -64,4 +67,32 @@ internal class FeltTest { 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/network/account/AccountTest.kt b/lib/src/test/kotlin/network/account/AccountTest.kt index bdd700d4e..b18546bb4 100644 --- a/lib/src/test/kotlin/network/account/AccountTest.kt +++ b/lib/src/test/kotlin/network/account/AccountTest.kt @@ -33,12 +33,14 @@ class AccountTest { private val signer = StarkCurveSigner(config.privateKey) private val constNonceAccountAddress = config.constNonceAccountAddress ?: config.accountAddress private val constNonceSigner = StarkCurveSigner(config.constNoncePrivateKey ?: config.privateKey) - private val provider = JsonRpcProvider(rpcUrl, StarknetChainId.TESTNET) + private val provider = JsonRpcProvider(rpcUrl) + private val cairoVersion = config.cairoVersion.toFelt val standardAccount = StandardAccount( accountAddress, signer, provider, + cairoVersion, ) // Note to future developers: @@ -48,16 +50,29 @@ class AccountTest { constNonceAccountAddress, constNonceSigner, provider, + cairoVersion, ) - private val accountContractClassHash = Felt.fromHex("0x05a9941d0cc16b8619a3325055472da709a66113afcc6a8ab86055da7d29c5f8") // Account contract written in Cairo 0, hence the same class hash for tesnet and integration. + private val predeclaredAccount = when (network) { + Network.GOERLI_INTEGRATION -> DeclaredAccount(Felt.fromHex("0x5a9941d0cc16b8619a3325055472da709a66113afcc6a8ab86055da7d29c5f8"), Felt.ZERO) + Network.GOERLI_TESTNET -> DeclaredAccount(Felt.fromHex("0x5a9941d0cc16b8619a3325055472da709a66113afcc6a8ab86055da7d29c5f8"), Felt.ZERO) + Network.SEPOLIA_INTEGRATION -> DeclaredAccount(Felt.fromHex("0x2338634f11772ea342365abd5be9d9dc8a6f44f159ad782fdebd3db5d969738"), Felt.ONE) + Network.SEPOLIA_TESTNET -> DeclaredAccount(Felt.fromHex("0x4c6d6cf894f8bc96bb9c525e6853e5483177841f7388f74a46cfda6f028c755"), Felt.ONE) + } private val predeployedMapContractAddress = when (network) { - Network.INTEGRATION -> Felt.fromHex("0x05cd21d6b3952a869fda11fa9a5bd2657bd68080d3da255655ded47a81c8bd53") - Network.TESTNET -> Felt.fromHex("0x02BAe9749940E7b89613C1a21D9C832242447caA065D5A2b8AB08c0c469b3462") + Network.GOERLI_INTEGRATION -> Felt.fromHex("0x05cd21d6b3952a869fda11fa9a5bd2657bd68080d3da255655ded47a81c8bd53") + Network.GOERLI_TESTNET -> Felt.fromHex("0x2BAe9749940E7b89613C1a21D9C832242447caA065D5A2b8AB08c0c469b3462") + Network.SEPOLIA_TESTNET -> Felt.fromHex("0x06b248bde9ce00d69099304a527640bc9515a08f0b49e5168e2096656f207e1d") + Network.SEPOLIA_INTEGRATION -> Felt.fromHex("0x061bbcfc1e11d8de0efcb502f9e1163b4033c74c7977cbb2b8c545164236a88c") } - private val ethContractAddress = Felt.fromHex("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7") // Same for testnet and integration. + private val ethContractAddress = Felt.fromHex("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7") private val strkContractAddress = Felt.fromHex("0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d") - private val udcAddress = Felt.fromHex("0x41a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf") // Same for testnet and integration. + private val udcAddress = Felt.fromHex("0x41a78e741e5af2fec34b695679bc6891742439f7afb8484ecd7766661ad02bf") + + data class DeclaredAccount( + val classHash: Felt, + val cairoVersion: Felt, + ) } @Test @@ -71,7 +86,11 @@ class AccountTest { entrypoint = "put", calldata = listOf(Felt.fromHex("0x1D2C3B7A8"), Felt.fromHex("0x451")), ) - val estimateFeeRequest = account.estimateFee(listOf(call)) + val simulationFlags = emptySet() + val estimateFeeRequest = account.estimateFee( + listOf(call), + simulationFlags, + ) val estimateFeeResponse = estimateFeeRequest.send().first().overallFee assertTrue(estimateFeeResponse.value > Felt.ONE.value) } @@ -105,7 +124,7 @@ class AccountTest { classHash = classHash, senderAddress = declareTransactionPayload.senderAddress, contractDefinition = declareTransactionPayload.contractDefinition, - chainId = provider.chainId, + chainId = provider.getChainId().send(), nonce = nonce, maxFee = declareTransactionPayload.maxFee, signature = declareTransactionPayload.signature, @@ -151,7 +170,7 @@ class AccountTest { senderAddress = declareTransactionPayload.senderAddress, contractDefinition = declareTransactionPayload.contractDefinition, casmContractDefinition = casmContractDefinition, - chainId = provider.chainId, + chainId = provider.getChainId().send(), nonce = nonce, maxFee = declareTransactionPayload.maxFee, signature = declareTransactionPayload.signature, @@ -314,6 +333,9 @@ class AccountTest { // Note to future developers experiencing experiencing failures in this test. // This test sometimes fails due to getNonce receiving higher (pending) nonce than addDeclareTransaction expects + // TODO: (#384) Test v3 transactions on Sepolia + assumeTrue(network == Network.GOERLI_INTEGRATION) + val account = standardAccount ScarbClient.createSaltedContract( @@ -361,13 +383,16 @@ class AccountTest { val call = Call( contractAddress = predeployedMapContractAddress, entrypoint = "put", - calldata = listOf(Felt.fromHex("0x1D2C3B7A8"), Felt.fromHex("0x451")), + calldata = listOf( + Felt.fromHex("0x1D2C3B7A8"), + Felt.fromHex("0x451"), + ), ) - val invokeRequest = account.execute(call) + val invokeRequest = account.execute(call, Felt(1000000000000000L)) val invokeResponse = invokeRequest.send() - Thread.sleep(30000) + Thread.sleep(20000) val receipt = provider.getTransactionReceipt(invokeResponse.transactionHash).send() assertTrue(receipt.isAccepted) @@ -379,6 +404,9 @@ class AccountTest { // Note to future developers experiencing experiencing failures in this test. // This test sometimes fails due to getNonce receiving higher (pending) nonce than addInvokeTransaction expects + // TODO: (#384) Test v3 transactions on Sepolia + assumeTrue(network == Network.GOERLI_INTEGRATION) + val account = standardAccount val call = Call( @@ -408,7 +436,7 @@ class AccountTest { calldata = listOf(Felt.fromHex("0x1D2C3B7A8")), ) - val getRequest = provider.callContract(call, BlockTag.LATEST) + val getRequest = provider.callContract(call) val getResponse = getRequest.send() val value = getResponse.first() assertNotEquals(Felt.ZERO, value) @@ -421,7 +449,7 @@ class AccountTest { val privateKey = Felt(System.currentTimeMillis()) val publicKey = StarknetCurve.getPublicKey(privateKey) - val classHash = accountContractClassHash + val (classHash, cairoVersion) = predeclaredAccount val salt = Felt(System.currentTimeMillis()) @@ -436,6 +464,7 @@ class AccountTest { address, privateKey, provider, + cairoVersion, ) val payloadForFeeEstimation = account.signDeployAccount( @@ -505,7 +534,7 @@ class AccountTest { val privateKey = Felt(System.currentTimeMillis()) val publicKey = StarknetCurve.getPublicKey(privateKey) - val classHash = accountContractClassHash + val (classHash, cairoVersion) = predeclaredAccount val salt = Felt(System.currentTimeMillis()) val calldata = listOf(publicKey) val deployedAccountAddress = ContractAddressCalculator.calculateAddressFromHash( @@ -518,6 +547,7 @@ class AccountTest { deployedAccountAddress, privateKey, provider, + cairoVersion, ) val deployMaxFee = Uint256(5523000060522) @@ -572,12 +602,15 @@ class AccountTest { fun `sign and send deploy account v3 transaction`() { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = true)) + // TODO: (#384) Test v3 transactions on Sepolia + assumeTrue(network == Network.GOERLI_INTEGRATION) + val account = standardAccount val privateKey = Felt(System.currentTimeMillis()) val publicKey = StarknetCurve.getPublicKey(privateKey) - val classHash = accountContractClassHash + val (classHash, cairoVersion) = predeclaredAccount val salt = Felt(System.currentTimeMillis()) val calldata = listOf(publicKey) val deployedAccountAddress = ContractAddressCalculator.calculateAddressFromHash( @@ -590,6 +623,7 @@ class AccountTest { deployedAccountAddress, privateKey, provider, + cairoVersion, ) val payloadForFeeEstimate = deployedAccount.signDeployAccount( classHash = classHash, @@ -689,12 +723,9 @@ class AccountTest { ) val invokeTx2 = account.sign(call2, params2) - val simulationFlags = when (network) { - // Pathfinder currently always requires SKIP_FEE_CHARGE flag - Network.INTEGRATION -> setOf(SimulationFlag.SKIP_FEE_CHARGE) - // Juno currently always fails on simulating invoke when SKIP_FEE_CHARGE flag is passed - Network.TESTNET -> emptySet() - } + // Use SKIP_FEE_CHARGE flag to avoid failure due to insufficient funds + val simulationFlags = setOf(SimulationFlag.SKIP_FEE_CHARGE) + val simulationResult = provider.simulateTransactions( transactions = listOf(invokeTx, invokeTx2), blockTag = BlockTag.LATEST, @@ -707,24 +738,21 @@ class AccountTest { assertTrue(simulationResult[1].transactionTrace is RevertedInvokeTransactionTrace) assertNotNull((simulationResult[1].transactionTrace as RevertedInvokeTransactionTrace).executeInvocation.revertReason) - // Juno currently does not support SKIP_VALIDATE flag - if (network != Network.TESTNET) { - val invokeTxWithoutSignature = InvokeTransactionV1Payload(invokeTx.senderAddress, invokeTx.calldata, emptyList(), invokeTx.maxFee, invokeTx.version, invokeTx.nonce) - val invokeTxWihtoutSignature2 = InvokeTransactionV1Payload(invokeTx2.senderAddress, invokeTx2.calldata, emptyList(), invokeTx2.maxFee, invokeTx2.version, invokeTx2.nonce) - val simulationFlags2 = setOf(SimulationFlag.SKIP_FEE_CHARGE, SimulationFlag.SKIP_VALIDATE) - val simulationResult2 = provider.simulateTransactions( - transactions = listOf(invokeTxWithoutSignature, invokeTxWihtoutSignature2), - blockTag = BlockTag.LATEST, - simulationFlags = simulationFlags2, - ).send() - - assertEquals(2, simulationResult2.size) - assertTrue(simulationResult[0].transactionTrace is InvokeTransactionTraceBase) - assertTrue(simulationResult[0].transactionTrace is InvokeTransactionTrace) - assertTrue(simulationResult[1].transactionTrace is InvokeTransactionTraceBase) - assertTrue(simulationResult[1].transactionTrace is RevertedInvokeTransactionTrace) - assertNotNull((simulationResult[1].transactionTrace as RevertedInvokeTransactionTrace).executeInvocation.revertReason) - } + val invokeTxWithoutSignature = InvokeTransactionV1Payload(invokeTx.senderAddress, invokeTx.calldata, emptyList(), invokeTx.maxFee, invokeTx.version, invokeTx.nonce) + val invokeTxWihtoutSignature2 = InvokeTransactionV1Payload(invokeTx2.senderAddress, invokeTx2.calldata, emptyList(), invokeTx2.maxFee, invokeTx2.version, invokeTx2.nonce) + val simulationFlags2 = setOf(SimulationFlag.SKIP_FEE_CHARGE, SimulationFlag.SKIP_VALIDATE) + val simulationResult2 = provider.simulateTransactions( + transactions = listOf(invokeTxWithoutSignature, invokeTxWihtoutSignature2), + blockTag = BlockTag.LATEST, + simulationFlags = simulationFlags2, + ).send() + + assertEquals(2, simulationResult2.size) + assertTrue(simulationResult[0].transactionTrace is InvokeTransactionTraceBase) + assertTrue(simulationResult[0].transactionTrace is InvokeTransactionTrace) + assertTrue(simulationResult[1].transactionTrace is InvokeTransactionTraceBase) + assertTrue(simulationResult[1].transactionTrace is RevertedInvokeTransactionTrace) + assertNotNull((simulationResult[1].transactionTrace as RevertedInvokeTransactionTrace).executeInvocation.revertReason) } @Test @@ -734,12 +762,12 @@ class AccountTest { val privateKey = Felt(System.currentTimeMillis()) val publicKey = StarknetCurve.getPublicKey(privateKey) - val classHash = accountContractClassHash + val (classHash, cairoVersion) = predeclaredAccount val salt = Felt(System.currentTimeMillis()) val calldata = listOf(publicKey) val deployedAccountAddress = ContractAddressCalculator.calculateAddressFromHash(classHash, calldata, salt) - val deployedAccount = StandardAccount(deployedAccountAddress, privateKey, provider) + val deployedAccount = StandardAccount(deployedAccountAddress, privateKey, provider, cairoVersion) val deployAccountTx = deployedAccount.signDeployAccount( classHash = classHash, salt = salt, @@ -747,8 +775,7 @@ class AccountTest { maxFee = Felt(1_000_000_000_000_000), ) - // Pathfinder currently always requires SKIP_FEE_CHARGE flag - // Juno currently fails on deploy account simulated transaction with MaxFeeExceedsBalance without SKIP_FEE_CHARGE flag + // Use SKIP_FEE_CHARGE flag to avoid having to transfer funds to the account val simulationFlags = setOf(SimulationFlag.SKIP_FEE_CHARGE) val simulationResult = provider.simulateTransactions( @@ -759,20 +786,17 @@ class AccountTest { assertEquals(1, simulationResult.size) assertTrue(simulationResult[0].transactionTrace is DeployAccountTransactionTrace) - // Juno currently does not support SKIP_VALIDATE flag - if (network != Network.TESTNET) { - val deployAccountTxWithoutSignature = DeployAccountTransactionV1Payload(deployAccountTx.classHash, deployAccountTx.salt, deployAccountTx.constructorCalldata, deployAccountTx.version, deployAccountTx.nonce, deployAccountTx.maxFee, emptyList()) + val deployAccountTxWithoutSignature = DeployAccountTransactionV1Payload(deployAccountTx.classHash, deployAccountTx.salt, deployAccountTx.constructorCalldata, deployAccountTx.version, deployAccountTx.nonce, deployAccountTx.maxFee, emptyList()) - val simulationFlags2 = setOf(SimulationFlag.SKIP_FEE_CHARGE, SimulationFlag.SKIP_VALIDATE) - val simulationResult2 = provider.simulateTransactions( - transactions = listOf(deployAccountTxWithoutSignature), - blockTag = BlockTag.LATEST, - simulationFlags = simulationFlags2, - ).send() + val simulationFlags2 = setOf(SimulationFlag.SKIP_FEE_CHARGE, SimulationFlag.SKIP_VALIDATE) + val simulationResult2 = provider.simulateTransactions( + transactions = listOf(deployAccountTxWithoutSignature), + blockTag = BlockTag.LATEST, + simulationFlags = simulationFlags2, + ).send() - assertEquals(1, simulationResult2.size) - assertTrue(simulationResult[0].transactionTrace is DeployAccountTransactionTrace) - } + assertEquals(1, simulationResult2.size) + assertTrue(simulationResult[0].transactionTrace is DeployAccountTransactionTrace) } @Test @@ -801,7 +825,7 @@ class AccountTest { ), ) - // Pathfinder currently always requires SKIP_FEE_CHARGE flag + // Use SKIP_FEE_CHARGE flag to avoid failure due to insufficient funds val simulationFlags = setOf(SimulationFlag.SKIP_FEE_CHARGE) val simulationResult = provider.simulateTransactions( transactions = listOf(declareTransactionPayload), @@ -840,7 +864,7 @@ class AccountTest { ), ) - // Pathfinder currently always requires SKIP_FEE_CHARGE flag + // Use SKIP_FEE_CHARGE flag to avoid failure due to insufficient funds val simulationFlags = setOf(SimulationFlag.SKIP_FEE_CHARGE) val simulationResult = provider.simulateTransactions( transactions = listOf(declareTransactionPayload), @@ -856,7 +880,13 @@ class AccountTest { fun `test udc deploy with parameters`() { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = true)) - val classHash = Felt.fromHex("0x353434f1495ca9a9943cab1c093fb765179163210b8d513613660ff371a5490") // cairo 0 contract, hence the same class hash for tesnet and integration. + assumeFalse(network == Network.GOERLI_INTEGRATION) + val classHash = when (network) { + Network.GOERLI_TESTNET -> Felt.fromHex("0x40971cb2233ff5680dc329121e03ae4af48082cf02d1082bcd07179610af39e") + Network.SEPOLIA_TESTNET -> Felt.fromHex("0x040971cb2233ff5680dc329121e03ae4af48082cf02d1082bcd07179610af39e") + Network.SEPOLIA_INTEGRATION -> Felt.fromHex("0x040971cb2233ff5680dc329121e03ae4af48082cf02d1082bcd07179610af39e") + else -> throw NotImplementedError("Test is not yet supported for this network $network") + } val account = standardAccount val deployer = StandardDeployer(udcAddress, provider, account) @@ -864,7 +894,7 @@ class AccountTest { val deployment = deployer.deployContract( classHash = classHash, constructorCalldata = emptyList(), - maxFee = Felt(4340000039060 * 2), + maxFee = Felt(1000000000000000L), unique = true, salt = Felt(System.currentTimeMillis()), ).send() @@ -878,10 +908,12 @@ class AccountTest { fun `test udc deploy with constructor`() { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = true)) - assumeTrue(network == Network.TESTNET) + assumeFalse(network == Network.GOERLI_INTEGRATION) val classHash = when (network) { - Network.TESTNET -> Felt.fromHex("0x31de86764e5a6694939a87321dad5769d427790147a4ee96497ba21102c8af9") - else -> throw IllegalStateException("Unsupported network: $network") + Network.GOERLI_TESTNET -> Felt.fromHex("0x31de86764e5a6694939a87321dad5769d427790147a4ee96497ba21102c8af9") + Network.SEPOLIA_TESTNET -> Felt.fromHex("0x8448a68b5ea1affc45e3fd4b8b480ea36a51dc34e337a16d2567d32d0c6f8a") + Network.SEPOLIA_INTEGRATION -> Felt.fromHex("0x31de86764e5a6694939a87321dad5769d427790147a4ee96497ba21102c8af9") + else -> throw NotImplementedError("Test is not yet supported for this network $network") } val account = standardAccount @@ -891,7 +923,7 @@ class AccountTest { val deployment = deployer.deployContract( classHash = classHash, constructorCalldata = listOf(initialBalance), - maxFee = Felt(4340000039060 * 2), + maxFee = Felt(1000000000000000L), ).send() Thread.sleep(120000) diff --git a/lib/src/test/kotlin/network/provider/ProviderTest.kt b/lib/src/test/kotlin/network/provider/ProviderTest.kt index 893afeb0e..bc75341aa 100644 --- a/lib/src/test/kotlin/network/provider/ProviderTest.kt +++ b/lib/src/test/kotlin/network/provider/ProviderTest.kt @@ -19,7 +19,71 @@ class ProviderTest { private val network = config.network private val rpcUrl = config.rpcUrl - private val provider = JsonRpcProvider(rpcUrl, StarknetChainId.TESTNET) + private val provider = JsonRpcProvider(rpcUrl) + + private val declareV0TransactionHash = when (network) { + Network.GOERLI_INTEGRATION -> Felt.fromHex("0x6d346ba207eb124355960c19c737698ad37a3c920a588b741e0130ff5bd4d6d") + Network.GOERLI_TESTNET -> Felt.fromHex("0x6d346ba207eb124355960c19c737698ad37a3c920a588b741e0130ff5bd4d6d") + Network.SEPOLIA_INTEGRATION -> Felt.fromHex("0x76b8ab51555253c7fcbcf2f8419b2576160160daf01ffb7c882e448e24b64ff") + Network.SEPOLIA_TESTNET -> Felt.fromHex("0x656e113cb27707d2147c271a79c51d1069b0273ae447b965e15154a17b3ec01") + } + private val invokeV1TransactionHash = when (network) { + Network.GOERLI_INTEGRATION -> Felt.fromHex("0x34223514e92989608e3b36f2a2a53011fa0699a275d7936a18921a11963c792") + Network.GOERLI_TESTNET -> Felt.fromHex("0x72776cb6462e7e1268bd93dee8ad2df5ee0abed955e3010182161bdb0daea62") + Network.SEPOLIA_INTEGRATION -> Felt.fromHex("0x3d381262ca26570083eab24e431b72e69ce5e33b423c034aef466613ee20511") + Network.SEPOLIA_TESTNET -> Felt.fromHex("0x03f6e39d90aa084585ac59fa4c19429499951eb7a279427bbe0a7718c8d9072f") + } + private val revertedInvokeV1TransactionHash = when (network) { + Network.GOERLI_INTEGRATION -> Felt.fromHex("0x5e2e61a59e3f254f2c65109344be985dff979abd01b9c15b659a95f466689bf") + Network.GOERLI_TESTNET -> Felt.fromHex("0x6bf08a6547a8be3cd3d718a068c2c0e9d3820252935f766c1ba6dd46f62e05") + Network.SEPOLIA_INTEGRATION -> Felt.fromHex("0xe691cd69a7dc7efb815f6029db26cf5d7a14f2b5e893e2de4a281c82b5a0d") + Network.SEPOLIA_TESTNET -> Felt.fromHex("0x7246ea24cefc572096264f1f243cd9b32837c17324ac23076070f29f50b6393") + } + private val deployAccountV1TransactionHash = when (network) { + Network.GOERLI_INTEGRATION -> Felt.fromHex("0x029da9f8997ce580718fa02ed0bd628976418b30a0c5c542510aaef21a4445e4") + Network.GOERLI_TESTNET -> Felt.fromHex("0xa8f359bad1181a37e41479b70a5c69a34e824b90accf8fbfba022708b7f08f") + Network.SEPOLIA_INTEGRATION -> Felt.fromHex("0x014f73658da451dec4d14de51e12ad79b737c6342814b5f05c39da83a9ec1f3c") + Network.SEPOLIA_TESTNET -> Felt.fromHex("0x62e87178d0bf221e453276d607420fd256d928349c620f08958eeb66f24d2d9") + } + private val declareV1TransactionHash = when (network) { + Network.GOERLI_INTEGRATION -> Felt.fromHex("0x417ec8ece9d2d2e68307069fdcde3c1fd8b0713b8a2687b56c19455c6ea85c1") + Network.GOERLI_TESTNET -> Felt.fromHex("0x6801a86a4a6873f62aaa478151ba03171691edde897c434ec8cf9db3bb77573") + Network.SEPOLIA_TESTNET -> Felt.fromHex("0x5e27aad6f9139f6eeb0ee886179c40b551e91ad8bcc80e16ff0fe6d5444d6f9") + Network.SEPOLIA_INTEGRATION -> Felt.fromHex("0x012bc00eadd7f25a5523e5857da2073e2028070a5e616723931ac290aba3f22a") + } + private val declareV2TranasctionHash = when (network) { + Network.GOERLI_INTEGRATION -> Felt.fromHex("0x70fac6862a52000d2d63a1c845c26c9202c9030921b4607818a0820a46eab26") + Network.GOERLI_TESTNET -> Felt.fromHex("0x747a364442ed4d72cd24d7e26f2c6ab0bc98c0a835f2276cd2bc07266331555") + Network.SEPOLIA_INTEGRATION -> Felt.fromHex("0x01556b67a22bc26dfc4827286997e3e3b53380e14ba1d879f1d67b7ffbd5a808") + Network.SEPOLIA_TESTNET -> Felt.fromHex("0x0683e900e4c0e27e164f0b7569f86edec6dec919e55d97728113b40fe6b731c7") + } + private val deployAccountV3TransactionHash by lazy { + when (network) { + Network.GOERLI_INTEGRATION -> Felt.fromHex("0x7c1ca558aaec1a14a4c0553517013631fad81c48667a3bcd635617c2560276") + else -> throw NotImplementedError("Test is not yet supported for this network: $network") + } + } + private val invokeV3TransactionHash by lazy { + when (network) { + Network.GOERLI_INTEGRATION -> Felt.fromHex("0x06f99b0650eb02eaf16cc97820075b1dc8c8a4ada22ef0a606f3c0b066d7ce07") + else -> throw NotImplementedError("Test is not yet supported for this network: $network") + } + } + private val declareV3TransactionHash by lazy { + when (network) { + Network.GOERLI_INTEGRATION -> Felt.fromHex("0x86693a36721bb586bee1f8c8b9ea33fbbb7f820dde48d9068dfa94a99ef53") + else -> throw NotImplementedError("Test is not yet supported for this network: $network") + } + } + private val specificBlockHash = when (network) { + Network.GOERLI_INTEGRATION -> Felt.fromHex("0x164923d2819eb5dd207275b51348ea2ac6b46965290ffcdf89350c998f28048") + Network.GOERLI_TESTNET -> Felt.fromHex("0x42be1d27e55744ab5d43ee98b8feb9895e96a034d6bb742a8204f530c680f3c") + Network.SEPOLIA_INTEGRATION -> Felt.fromHex("0x3224282d7f577055cd72894cb66e511f105576788796a1d50538e7eae5efbe1") + Network.SEPOLIA_TESTNET -> Felt.fromHex("0x1e04294ce4f7dd489ba5b5618dc112b37f9a7e82e2ded5691fb3083839dd3b5") + } + + @Suppress("const") + private val specificBlockNumber = 1000 } @Test @@ -34,94 +98,46 @@ class ProviderTest { assertTrue(validPattern.containsMatchIn(specVersion)) } + @Test + fun `get chain id`() { + assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) + val request = provider.getChainId() + val chainId = request.send() + + 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 + } + assertEquals(expectedChainId, chainId) + } + @Test fun `get transaction status`() { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) - val transactionHash = when (network) { - Network.INTEGRATION -> Felt.fromHex("0x26396c032286bcefb54616581eea5c7e373f0a21c322c44912cfa0944a52926") - Network.TESTNET -> Felt.fromHex("0x72776cb6462e7e1268bd93dee8ad2df5ee0abed955e3010182161bdb0daea62") - } - val transactionHash2 = when (network) { - Network.INTEGRATION -> Felt.fromHex("0x5e2e61a59e3f254f2c65109344be985dff979abd01b9c15b659a95f466689bf") - Network.TESTNET -> Felt.fromHex("0x6bf08a6547a8be3cd3d718a068c2c0e9d3820252935f766c1ba6dd46f62e05") - } + val transactionHash = invokeV1TransactionHash + val transactionHash2 = revertedInvokeV1TransactionHash val transactionStatus = provider.getTransactionStatus(transactionHash).send() // TODO: Re-enable this assertion for integration once transaction appear as accepted on L1 again - if (network != Network.INTEGRATION) { - assertEquals(TransactionFinalityStatus.ACCEPTED_ON_L1, transactionStatus.finalityStatus) + if (network != Network.GOERLI_INTEGRATION) { + assertEquals(TransactionStatus.ACCEPTED_ON_L1, transactionStatus.finalityStatus) } assertNotNull(transactionStatus.executionStatus) assertEquals(TransactionExecutionStatus.SUCCEEDED, transactionStatus.executionStatus) val transactionStatus2 = provider.getTransactionStatus(transactionHash2).send() - // TODO: Re-enable this assertion for integration once transaction appear as accepted on L1 again - if (network != Network.INTEGRATION) { - assertEquals(TransactionFinalityStatus.ACCEPTED_ON_L1, transactionStatus2.finalityStatus) - } + assertNotNull(transactionStatus2.executionStatus) assertEquals(TransactionExecutionStatus.REVERTED, transactionStatus2.executionStatus) } - @Disabled - @Test - fun `estimate message fee`() { - assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) - - // TODO: (#344) Currently, Juno fails to estimate the message fee. - assumeFalse(network == Network.TESTNET) - - val gasConsumed = Felt(19931) - val gasPrice = Felt(1022979559) - val overallFee = Felt(20389005590429) - - val fromAddress = when (network) { - Network.INTEGRATION -> Felt.fromHex("0xbe1259ff905cadbbaa62514388b71bdefb8aacc1") - Network.TESTNET -> Felt.fromHex("0xf7d519a1660dd9237d47c039696fe4a2b93b6987") - } - val toAddress = when (network) { - Network.INTEGRATION -> Felt.fromHex("0x073314940630fd6dcda0d772d4c972c4e0a9946bef9dabf4ef84eda8ef542b82") - Network.TESTNET -> Felt.fromHex("0x0677d43766e880bfa6ddcf43e2ff54d54c64105e4a7fce20b7b1d40086a3a674") - } - val selector = when (network) { - Network.INTEGRATION -> Felt.fromHex("0x02d757788a8d8d6f21d1cd40bce38a8222d70654214e96ff95d8086e684fbee5") - Network.TESTNET -> Felt.fromHex("0x026490f901ea8ad5a245d987479919f1d20fbb0c164367e33ef09a9ea4ba8d04") - } - val message = MessageL1ToL2( - fromAddress = fromAddress, - toAddress = toAddress, - selector = selector, - payload = listOf( - Felt.fromHex("0x54d01e5fc6eb4e919ceaab6ab6af192e89d1beb4f29d916768c61a4d48e6c95"), - Felt.fromHex("0x38d7ea4c68000"), - Felt.fromHex("0x0"), - ), - ) - - val request = provider.getEstimateMessageFee( - message = message, - blockNumber = 306687, - ) - val response = request.send() - - assertNotNull(response) - assertNotNull(response.gasConsumed) - assertNotNull(response.gasPrice) - assertNotNull(response.overallFee) - - assertEquals(gasPrice, response.gasPrice) - assertEquals(gasConsumed, response.gasConsumed) - assertEquals(overallFee, response.overallFee) - } - @Test fun `get deploy account v1 transaction`() { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) - val transactionHash = when (network) { - Network.INTEGRATION -> Felt.fromHex("0x029da9f8997ce580718fa02ed0bd628976418b30a0c5c542510aaef21a4445e4") - Network.TESTNET -> Felt.fromHex("0xa8f359bad1181a37e41479b70a5c69a34e824b90accf8fbfba022708b7f08f") - } + val transactionHash = deployAccountV1TransactionHash val tx = provider.getTransaction(transactionHash).send() assertEquals(transactionHash, tx.hash) assertEquals(Felt.ONE, tx.version) @@ -138,11 +154,10 @@ class ProviderTest { fun `get deploy account v3 transaction`() { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) - assumeTrue(network == Network.INTEGRATION) - val transactionHash = when (network) { - Network.INTEGRATION -> Felt.fromHex("0x007c1ca558aaec1a14a4c0553517013631fad81c48667a3bcd635617c2560276") - Network.TESTNET -> throw NotImplementedError("No support for testing deploy account v3 on testnet") - } + // TODO: (#384) Test v3 transactions on Sepolia + assumeTrue(network == Network.GOERLI_INTEGRATION) + + val transactionHash = deployAccountV3TransactionHash val tx = provider.getTransaction(transactionHash).send() assertEquals(transactionHash, tx.hash) @@ -160,10 +175,7 @@ class ProviderTest { fun `get reverted invoke v1 transaction`() { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) - val transactionHash = when (network) { - Network.INTEGRATION -> Felt.fromHex("0x5e2e61a59e3f254f2c65109344be985dff979abd01b9c15b659a95f466689bf") - Network.TESTNET -> Felt.fromHex("0x6bf08a6547a8be3cd3d718a068c2c0e9d3820252935f766c1ba6dd46f62e05") - } + val transactionHash = revertedInvokeV1TransactionHash val tx = provider.getTransaction(transactionHash).send() assertEquals(transactionHash, tx.hash) @@ -173,10 +185,6 @@ class ProviderTest { assertTrue(receipt is ProcessedInvokeTransactionReceipt) assertFalse(receipt.isAccepted) assertEquals(TransactionExecutionStatus.REVERTED, receipt.executionStatus) - // TODO: Re-enable this assertion for integration once transaction appear as accepted on L1 again - if (network != Network.INTEGRATION) { - assertEquals(TransactionFinalityStatus.ACCEPTED_ON_L1, receipt.finalityStatus) - } assertNotNull(receipt.revertReason) } @@ -184,10 +192,7 @@ class ProviderTest { fun `get invoke v1 transaction with events`() { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) - val transactionHash = when (network) { - Network.INTEGRATION -> Felt.fromHex("0x34223514e92989608e3b36f2a2a53011fa0699a275d7936a18921a11963c792") - Network.TESTNET -> Felt.fromHex("0x72776cb6462e7e1268bd93dee8ad2df5ee0abed955e3010182161bdb0daea62") - } + val transactionHash = invokeV1TransactionHash val tx = provider.getTransaction(transactionHash).send() assertTrue(tx is InvokeTransaction) assertEquals(transactionHash, tx.hash) @@ -197,7 +202,7 @@ class ProviderTest { val receipt = receiptRequest.send() assertTrue(receipt.isAccepted) - assertTrue(receipt.events.size > 2) + assertTrue(receipt.events.size >= 2) assertTrue(receipt.isAccepted) assertNull(receipt.revertReason) @@ -209,11 +214,10 @@ class ProviderTest { fun `get invoke v3 transaction with events`() { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) - assumeTrue(network == Network.INTEGRATION) - val transactionHash = when (network) { - Network.INTEGRATION -> Felt.fromHex("0x06f99b0650eb02eaf16cc97820075b1dc8c8a4ada22ef0a606f3c0b066d7ce07") - Network.TESTNET -> throw NotImplementedError("No support for testing deploy account v3 on testnet") - } + // TODO: (#384) Test v3 transactions on Sepolia + assumeTrue(network == Network.GOERLI_INTEGRATION) + + val transactionHash = invokeV3TransactionHash val tx = provider.getTransaction(transactionHash).send() assertTrue(tx is InvokeTransaction) @@ -237,7 +241,7 @@ class ProviderTest { fun `get declare v0 transaction`() { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) - val transactionHash = Felt.fromHex("0x6d346ba207eb124355960c19c737698ad37a3c920a588b741e0130ff5bd4d6d") + val transactionHash = declareV0TransactionHash val tx = provider.getTransaction(transactionHash).send() as DeclareTransactionV0 assertEquals(transactionHash, tx.hash) assertNotEquals(Felt.ZERO, tx.classHash) @@ -248,7 +252,7 @@ class ProviderTest { assertTrue(receipt.isAccepted) // TODO: Re-enable this assertion for integration once transaction appear as accepted on L1 again - if (network != Network.INTEGRATION) { + if (network != Network.GOERLI_INTEGRATION) { assertEquals(TransactionFinalityStatus.ACCEPTED_ON_L1, receipt.finalityStatus) } assertNull(receipt.revertReason) @@ -262,10 +266,7 @@ class ProviderTest { fun `get declare v1 transaction`() { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) - val transactionHash = when (network) { - Network.INTEGRATION -> Felt.fromHex("0x0417ec8ece9d2d2e68307069fdcde3c1fd8b0713b8a2687b56c19455c6ea85c1") - Network.TESTNET -> Felt.fromHex("0x6801a86a4a6873f62aaa478151ba03171691edde897c434ec8cf9db3bb77573") - } + val transactionHash = declareV1TransactionHash val tx = provider.getTransaction(transactionHash).send() as DeclareTransactionV1 assertNotEquals(Felt.ZERO, tx.classHash) assertEquals(transactionHash, tx.hash) @@ -276,10 +277,7 @@ class ProviderTest { assertTrue(receipt is ProcessedDeclareTransactionReceipt) assertTrue(receipt.isAccepted) assertEquals(TransactionExecutionStatus.SUCCEEDED, receipt.executionStatus) - // TODO: Re-enable this assertion for integration once transaction appear as accepted on L1 again - if (network != Network.INTEGRATION) { - assertEquals(TransactionFinalityStatus.ACCEPTED_ON_L1, receipt.finalityStatus) - } + assertEquals(TransactionFinalityStatus.ACCEPTED_ON_L1, receipt.finalityStatus) assertNull(receipt.revertReason) } @@ -287,10 +285,7 @@ class ProviderTest { fun `get declare v2 transaction`() { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) - val transactionHash = when (network) { - Network.INTEGRATION -> Felt.fromHex("0x70fac6862a52000d2d63a1c845c26c9202c9030921b4607818a0820a46eab26") - Network.TESTNET -> Felt.fromHex("0x747a364442ed4d72cd24d7e26f2c6ab0bc98c0a835f2276cd2bc07266331555") - } + val transactionHash = declareV2TranasctionHash val tx = provider.getTransaction(transactionHash).send() as DeclareTransactionV2 assertNotEquals(Felt.ZERO, tx.classHash) assertEquals(transactionHash, tx.hash) @@ -307,11 +302,10 @@ class ProviderTest { fun `get declare v3 transaction`() { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) - assumeTrue(network == Network.INTEGRATION) - val transactionHash = when (network) { - Network.INTEGRATION -> Felt.fromHex("0x86693a36721bb586bee1f8c8b9ea33fbbb7f820dde48d9068dfa94a99ef53") - Network.TESTNET -> throw NotImplementedError("No support for testing deploy account v3 on testnet") - } + // TODO: (#384) Test v3 transactions on Sepolia + assumeTrue(network == Network.GOERLI_INTEGRATION) + + val transactionHash = declareV3TransactionHash val tx = provider.getTransaction(transactionHash).send() as DeclareTransactionV3 assertNotEquals(Felt.ZERO, tx.classHash) @@ -330,8 +324,10 @@ class ProviderTest { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) val transactionHash = when (network) { - Network.INTEGRATION -> Felt.fromHex("0x5753d979e05f7c079b04c8fdafe2b6f4951492b6509f66f1d86e7c061882ee3") - Network.TESTNET -> Felt.fromHex("0x47ca5f1e16ba2cf997ebc33e60dfa3e5323fb3eebf63b0b9319fb4f6174ade8") + Network.GOERLI_INTEGRATION -> Felt.fromHex("0x5753d979e05f7c079b04c8fdafe2b6f4951492b6509f66f1d86e7c061882ee3") + Network.GOERLI_TESTNET -> Felt.fromHex("0x47ca5f1e16ba2cf997ebc33e60dfa3e5323fb3eebf63b0b9319fb4f6174ade8") + Network.SEPOLIA_INTEGRATION -> Felt.fromHex("0x2c678e2dda58eb4bffd1f2c45cca6a883e6f388e91aa5e153ff09e3f52a0dc5") + Network.SEPOLIA_TESTNET -> Felt.fromHex("0x785c2ada3f53fbc66078d47715c27718f92e6e48b96372b36e5197de69b82b5") } val tx = provider.getTransaction(transactionHash).send() assertTrue(tx is L1HandlerTransaction) @@ -345,8 +341,10 @@ class ProviderTest { assertNull(receipt.revertReason) val expectedMessageHash = when (network) { - Network.TESTNET -> NumAsHex.fromHex("0x6411d0d085d25a8da5f53b45f616d8c8473c12d5af0e9ed84515af0a58a28bf1") - Network.INTEGRATION -> NumAsHex.fromHex("0xf6359249ccef7caea9158c76133893d8bcbc09701df4caf111e7e2fc1283eb08") + Network.GOERLI_TESTNET -> NumAsHex.fromHex("0x6411d0d085d25a8da5f53b45f616d8c8473c12d5af0e9ed84515af0a58a28bf1") + Network.GOERLI_INTEGRATION -> NumAsHex.fromHex("0xf6359249ccef7caea9158c76133893d8bcbc09701df4caf111e7e2fc1283eb08") + Network.SEPOLIA_INTEGRATION -> NumAsHex.fromHex("0x62aadcf51c6b5d9169523f4f62baae7a50c7fb4915b3789c044545af6e6b039c") + Network.SEPOLIA_TESTNET -> NumAsHex.fromHex("0x42e76df4e3d5255262929c27132bd0d295a8d3db2cfe63d2fcd061c7a7a7ab34") } assertEquals(expectedMessageHash, (receipt as ProcessedL1HandlerTransactionReceipt).messageHash) @@ -357,8 +355,10 @@ class ProviderTest { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) val transactionHash = when (network) { - Network.INTEGRATION -> Felt.fromHex("0x157438780a13f8cdfa5c291d666361c112ac0082751fac480e520a7bd78af6d") - Network.TESTNET -> Felt.fromHex("0xd73488307e92d91ddf1a84b5670b37d3b1598e56096ad9be9925597133b681") + Network.GOERLI_INTEGRATION -> Felt.fromHex("0x157438780a13f8cdfa5c291d666361c112ac0082751fac480e520a7bd78af6d") + Network.GOERLI_TESTNET -> Felt.fromHex("0xd73488307e92d91ddf1a84b5670b37d3b1598e56096ad9be9925597133b681") + Network.SEPOLIA_TESTNET -> Felt.fromHex("0x9ce93eba4c0201940e229cb899fc8822a447ad48ed5e61c929b4e7c9f6ace9") + Network.SEPOLIA_INTEGRATION -> Felt.fromHex("0x26cda254979ce4e9705b83a886e175f5194b89339ce7de4bbae9ea6c9966c6d") } val receiptRequest = provider.getTransactionReceipt(transactionHash) @@ -404,10 +404,7 @@ class ProviderTest { fun `get block with transactions with block hash`() { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) - val blockHash = when (network) { - Network.INTEGRATION -> Felt.fromHex("0x164923d2819eb5dd207275b51348ea2ac6b46965290ffcdf89350c998f28048") - Network.TESTNET -> Felt.fromHex("0x42be1d27e55744ab5d43ee98b8feb9895e96a034d6bb742a8204f530c680f3c") - } + val blockHash = specificBlockHash val request = provider.getBlockWithTxs(blockHash) val response = request.send() @@ -420,7 +417,7 @@ class ProviderTest { fun `get block with transactions with block number`() { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) - val blockNumber = 310252 + val blockNumber = specificBlockNumber val request = provider.getBlockWithTxs(blockNumber) val response = request.send() @@ -460,10 +457,7 @@ class ProviderTest { fun `get block with transaction hashes with block hash`() { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) - val blockHash = when (network) { - Network.INTEGRATION -> Felt.fromHex("0x164923d2819eb5dd207275b51348ea2ac6b46965290ffcdf89350c998f28048") - Network.TESTNET -> Felt.fromHex("0x42be1d27e55744ab5d43ee98b8feb9895e96a034d6bb742a8204f530c680f3c") - } + val blockHash = specificBlockHash val request = provider.getBlockWithTxHashes(blockHash) val response = request.send() @@ -476,7 +470,7 @@ class ProviderTest { fun `get block with transaction hashes with block number`() { assumeTrue(NetworkConfig.isTestEnabled(requiresGas = false)) - val blockNumber = 310252 + val blockNumber = specificBlockNumber val request = provider.getBlockWithTxHashes(blockNumber) val response = request.send() diff --git a/lib/src/test/kotlin/network/utils/NetworkConfig.kt b/lib/src/test/kotlin/network/utils/NetworkConfig.kt index 164f708a7..cc8d16b5a 100644 --- a/lib/src/test/kotlin/network/utils/NetworkConfig.kt +++ b/lib/src/test/kotlin/network/utils/NetworkConfig.kt @@ -8,13 +8,16 @@ class NetworkConfig { val rpcUrl: String, val accountAddress: Felt, val privateKey: Felt, + val cairoVersion: Int = 0, val constNonceAccountAddress: Felt? = null, val constNoncePrivateKey: Felt? = null, ) enum class Network(val value: String) { - INTEGRATION("INTEGRATION"), - TESTNET("TESTNET"), + GOERLI_INTEGRATION("GOERLI_INTEGRATION"), + GOERLI_TESTNET("GOERLI_TESTNET"), + SEPOLIA_INTEGRATION("SEPOLIA_INTEGRATION"), + SEPOLIA_TESTNET("SEPOLIA_TESTNET"), } enum class NetworkTestMode { @@ -48,7 +51,7 @@ class NetworkConfig { private fun makeConfigFromEnv(): Config { if (testMode == NetworkTestMode.DISABLED) { return Config( - network = Network.INTEGRATION, + network = Network.GOERLI_INTEGRATION, rpcUrl = "", accountAddress = Felt.ZERO, privateKey = Felt.ZERO, @@ -64,6 +67,7 @@ class NetworkConfig { rpcUrl = "${network.value}_RPC_URL".let { env.getOrElse(it) { throw RuntimeException("$it not found in environment variables") } }, accountAddress = "${network.value}_ACCOUNT_ADDRESS".let { env.getOrElse(it) { throw RuntimeException("$it not found in environment variables") } }.let { Felt.fromHex(it) }, privateKey = "${network.value}_PRIVATE_KEY".let { env.getOrElse(it) { throw RuntimeException("$it not found in environment variables") } }.let { Felt.fromHex(it) }, + cairoVersion = env["${network.value}_ACCOUNT_CAIRO_VERSION"]?.toInt() ?: 0, constNonceAccountAddress = env["${network.value}_CONST_NONCE_ACCOUNT_ADDRESS"]?.let { Felt.fromHex(it) }, constNoncePrivateKey = env["${network.value}_CONST_NONCE_PRIVATE_KEY"]?.let { Felt.fromHex(it) }, ) diff --git a/lib/src/test/kotlin/starknet/account/StandardAccountTest.kt b/lib/src/test/kotlin/starknet/account/StandardAccountTest.kt index eabb7e129..0e25df430 100644 --- a/lib/src/test/kotlin/starknet/account/StandardAccountTest.kt +++ b/lib/src/test/kotlin/starknet/account/StandardAccountTest.kt @@ -7,7 +7,6 @@ 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.toUint256 import com.swmansion.starknet.provider.exceptions.RequestFailedException import com.swmansion.starknet.provider.rpc.JsonRpcProvider import com.swmansion.starknet.service.http.HttpResponse @@ -41,7 +40,7 @@ class StandardAccountTest { contractsDirectory = Paths.get("src/test/resources/contracts"), ) private val rpcUrl = devnetClient.rpcUrl - private val provider = JsonRpcProvider(rpcUrl, StarknetChainId.TESTNET) + private val provider = JsonRpcProvider(rpcUrl) private val accountContractClassHash = DevnetClient.accountContractClassHash private lateinit var accountAddress: Felt @@ -57,10 +56,7 @@ class StandardAccountTest { try { devnetClient.start() - // TODO: (#371) instead, deploy manutally "standard_account_test" account - // and prefund it with STRK, once minting STRK is supported on devnet. - val accountDetails = DevnetClient.predeployedAccount1 - devnetClient.prefundAccountEth(accountDetails.address) + val accountDetails = devnetClient.deployAccount("standard_account_test", prefund = true).details balanceContractAddress = devnetClient.declareDeployContract("Balance", constructorCalldata = listOf(Felt(451))).contractAddress accountAddress = accountDetails.address @@ -219,7 +215,7 @@ class StandardAccountTest { classHash = classHash, senderAddress = declareTransactionPayload.senderAddress, contractDefinition = declareTransactionPayload.contractDefinition, - chainId = provider.chainId, + chainId = provider.getChainId().send(), nonce = nonce, maxFee = declareTransactionPayload.maxFee, signature = declareTransactionPayload.signature, @@ -439,7 +435,7 @@ class StandardAccountTest { """.trimIndent(), ) } - val provider = JsonRpcProvider(devnetClient.rpcUrl, StarknetChainId.TESTNET, httpService) + val provider = JsonRpcProvider(devnetClient.rpcUrl, httpService) val account = StandardAccount(Felt.ONE, Felt.ONE, provider) val typedData = loadTypedData("typed_data_struct_array_example.json") @@ -915,12 +911,7 @@ class StandardAccountTest { ) // Prefund the new account address with STRK - val transferCall = Call( - contractAddress = DevnetClient.strkErc20ContractAddress, - entrypoint = "transfer", - calldata = listOf(address) + l1ResourceBounds.toMaxFee().toUint256.toCalldata(), - ) - account.executeV3(transferCall).send() + devnetClient.prefundAccountStrk(address) val payload = newAccount.signDeployAccount( classHash = accountContractClassHash, @@ -1152,7 +1143,7 @@ class StandardAccountTest { val httpService = mock { on { send(any()) } doReturn HttpResponse(true, 200, mockedResponse) } - val mockProvider = JsonRpcProvider(devnetClient.rpcUrl, StarknetChainId.TESTNET, httpService) + val mockProvider = JsonRpcProvider(devnetClient.rpcUrl, httpService) val nonce = account.getNonce().send() val maxFee = Felt(1) diff --git a/lib/src/test/kotlin/starknet/data/types/TransactionsTest.kt b/lib/src/test/kotlin/starknet/data/types/TransactionsTest.kt index b813a7622..2c3f79fa9 100644 --- a/lib/src/test/kotlin/starknet/data/types/TransactionsTest.kt +++ b/lib/src/test/kotlin/starknet/data/types/TransactionsTest.kt @@ -16,7 +16,7 @@ internal class TransactionsTest { val tx1 = TransactionFactory.makeInvokeV1Transaction( senderAddress = Felt.fromHex("0x2a"), calldata = listOf(), - chainId = StarknetChainId.TESTNET, + chainId = StarknetChainId.GOERLI, nonce = Felt.ZERO, maxFee = Felt.ZERO, version = Felt.ONE, @@ -46,7 +46,7 @@ internal class TransactionsTest { BigInteger("2"), ), ), - chainId = StarknetChainId.TESTNET, + chainId = StarknetChainId.GOERLI, nonce = Felt.ZERO, maxFee = Felt(BigInteger("100000000")), version = Felt.ONE, diff --git a/lib/src/test/kotlin/starknet/deployercontract/StandardDeployerTest.kt b/lib/src/test/kotlin/starknet/deployercontract/StandardDeployerTest.kt index c8f04462b..53386edac 100644 --- a/lib/src/test/kotlin/starknet/deployercontract/StandardDeployerTest.kt +++ b/lib/src/test/kotlin/starknet/deployercontract/StandardDeployerTest.kt @@ -4,7 +4,6 @@ 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.StarknetChainId import com.swmansion.starknet.deployercontract.StandardDeployer import com.swmansion.starknet.provider.Provider import com.swmansion.starknet.provider.rpc.JsonRpcProvider @@ -25,10 +24,7 @@ object StandardDeployerTest { accountDirectory = Paths.get("src/test/resources/accounts/standard_deployer_test"), contractsDirectory = Paths.get("src/test/resources/contracts"), ) - private val provider = JsonRpcProvider( - devnetClient.rpcUrl, - StarknetChainId.TESTNET, - ) + private val provider = JsonRpcProvider(devnetClient.rpcUrl) private lateinit var signer: Signer diff --git a/lib/src/test/kotlin/starknet/provider/ProviderTest.kt b/lib/src/test/kotlin/starknet/provider/ProviderTest.kt index 793f12925..95ac34c10 100644 --- a/lib/src/test/kotlin/starknet/provider/ProviderTest.kt +++ b/lib/src/test/kotlin/starknet/provider/ProviderTest.kt @@ -25,7 +25,7 @@ class ProviderTest { contractsDirectory = Paths.get("src/test/resources/contracts"), ) val rpcUrl = devnetClient.rpcUrl - private val provider = JsonRpcProvider(rpcUrl, StarknetChainId.TESTNET) + private val provider = JsonRpcProvider(rpcUrl) private lateinit var balanceContractAddress: Felt private lateinit var balanceClassHash: Felt @@ -340,7 +340,7 @@ class ProviderTest { """.trimIndent(), ) } - val provider = JsonRpcProvider(rpcUrl, StarknetChainId.TESTNET, httpService) + val provider = JsonRpcProvider(rpcUrl, httpService) val request = provider.getTransactionReceipt(Felt.ZERO) val response = request.send() @@ -406,7 +406,7 @@ class ProviderTest { ) } - val provider = JsonRpcProvider(rpcUrl, StarknetChainId.TESTNET, httpService) + val provider = JsonRpcProvider(rpcUrl, httpService) val receipt = provider.getTransactionReceipt(Felt.fromHex("0x333198614194ae5b5ef921e63898a592de5e9f4d7b6e04745093da88b429f2a")).send() assertTrue(receipt is PendingTransactionReceipt) @@ -479,7 +479,7 @@ class ProviderTest { """.trimIndent(), ) } - val provider = JsonRpcProvider(rpcUrl, StarknetChainId.TESTNET, httpService) + val provider = JsonRpcProvider(rpcUrl, httpService) val request = provider.getTransactionReceipt(Felt.fromHex("0x4b2ff971b669e31c704fde5c1ad6ee08ba2000986a25ad5106ab94546f36f7")) val response = request.send() @@ -523,7 +523,7 @@ class ProviderTest { """.trimIndent(), ) } - val provider = JsonRpcProvider(rpcUrl, StarknetChainId.TESTNET, httpService) + val provider = JsonRpcProvider(rpcUrl, httpService) val request = provider.getTransaction(Felt.ZERO) val response = request.send() @@ -591,7 +591,7 @@ class ProviderTest { """.trimIndent(), ) } - val provider = JsonRpcProvider(rpcUrl, StarknetChainId.TESTNET, httpService) + val provider = JsonRpcProvider(rpcUrl, httpService) val request = provider.getTransaction(Felt.ZERO) val response = request.send() @@ -734,7 +734,7 @@ class ProviderTest { val httpService = mock { on { send(any()) } doReturn HttpResponse(true, 200, mockedResponse) } - val provider = JsonRpcProvider(rpcUrl, StarknetChainId.TESTNET, httpService) + val provider = JsonRpcProvider(rpcUrl, httpService) val request = provider.getSyncing() val response = request.send() @@ -747,6 +747,14 @@ class ProviderTest { assertEquals(10, response.highestBlockNumber) } + @Test + fun `get chain id`() { + val request = provider.getChainId() + val response = request.send() + + assertEquals(StarknetChainId.GOERLI, response) + } + @Test fun `get nonce with block tag`() { val request = provider.getNonce(balanceContractAddress, BlockTag.LATEST) @@ -821,7 +829,7 @@ class ProviderTest { val httpService = mock { on { send(any()) } doReturn HttpResponse(true, 200, mockedResponse) } - val provider = JsonRpcProvider(rpcUrl, StarknetChainId.TESTNET, httpService) + val provider = JsonRpcProvider(rpcUrl, httpService) val request = provider.getBlockWithTxs(BlockTag.PENDING) val response = request.send() @@ -884,7 +892,7 @@ class ProviderTest { val httpService = mock { on { send(any()) } doReturn HttpResponse(true, 200, mockedResponse) } - val provider = JsonRpcProvider(rpcUrl, StarknetChainId.TESTNET, httpService) + val provider = JsonRpcProvider(rpcUrl, httpService) val request = provider.getBlockWithTxHashes(BlockTag.PENDING) val response = request.send() @@ -950,7 +958,7 @@ class ProviderTest { val httpService = mock { on { send(any()) } doReturn HttpResponse(true, 200, mockedResponse) } - val provider = JsonRpcProvider(rpcUrl, StarknetChainId.TESTNET, httpService) + val provider = JsonRpcProvider(rpcUrl, httpService) val request = provider.getStateUpdate(BlockTag.PENDING) val response = request.send() diff --git a/lib/src/test/kotlin/starknet/provider/handlers/HttpErrorHandlerTest.kt b/lib/src/test/kotlin/starknet/provider/handlers/HttpErrorHandlerTest.kt index 9fcdc1d29..fd1c84f15 100644 --- a/lib/src/test/kotlin/starknet/provider/handlers/HttpErrorHandlerTest.kt +++ b/lib/src/test/kotlin/starknet/provider/handlers/HttpErrorHandlerTest.kt @@ -1,7 +1,6 @@ package starknet.provider.handlers import com.swmansion.starknet.data.types.Felt -import com.swmansion.starknet.data.types.StarknetChainId import com.swmansion.starknet.provider.exceptions.RequestFailedException import com.swmansion.starknet.provider.exceptions.RpcRequestFailedException import com.swmansion.starknet.provider.rpc.JsonRpcProvider @@ -21,7 +20,7 @@ class HttpErrorHandlerTest { val httpServiceMock = mock { on { send(any()) } doReturn HttpResponse(false, 500, message) } - val provider = JsonRpcProvider("", StarknetChainId.TESTNET, httpServiceMock) + val provider = JsonRpcProvider("", httpServiceMock) val request = provider.getTransaction(Felt(1)) val exception = assertThrows(RequestFailedException::class.java) { @@ -47,7 +46,7 @@ class HttpErrorHandlerTest { val httpServiceMock = mock { on { send(any()) } doReturn HttpResponse(true, 200, message) } - val provider = JsonRpcProvider("", StarknetChainId.TESTNET, httpServiceMock) + val provider = JsonRpcProvider("", httpServiceMock) val request = provider.getTransaction(Felt(1)) val exception = assertThrows(RpcRequestFailedException::class.java) { @@ -75,7 +74,7 @@ class HttpErrorHandlerTest { val httpServiceMock = mock { on { send(any()) } doReturn HttpResponse(true, 200, message) } - val provider = JsonRpcProvider("", StarknetChainId.TESTNET, httpServiceMock) + val provider = JsonRpcProvider("", httpServiceMock) val request = provider.getTransaction(Felt(1)) val exception = assertThrows(RpcRequestFailedException::class.java) { @@ -107,7 +106,7 @@ class HttpErrorHandlerTest { val httpServiceMock = mock { on { send(any()) } doReturn HttpResponse(true, 200, message) } - val provider = JsonRpcProvider("", StarknetChainId.TESTNET, httpServiceMock) + val provider = JsonRpcProvider("", httpServiceMock) val request = provider.getTransaction(Felt(1)) val exception = assertThrows(RpcRequestFailedException::class.java) { @@ -134,7 +133,7 @@ class HttpErrorHandlerTest { val httpServiceMock = mock { on { send(any()) } doReturn HttpResponse(true, 200, message) } - val provider = JsonRpcProvider("", StarknetChainId.TESTNET, httpServiceMock) + val provider = JsonRpcProvider("", httpServiceMock) val request = provider.getTransaction(Felt(1)) val exception = assertThrows(RpcRequestFailedException::class.java) { diff --git a/lib/src/test/kotlin/starknet/utils/DevnetClient.kt b/lib/src/test/kotlin/starknet/utils/DevnetClient.kt index 24aa1880e..8a9dcd8a8 100644 --- a/lib/src/test/kotlin/starknet/utils/DevnetClient.kt +++ b/lib/src/test/kotlin/starknet/utils/DevnetClient.kt @@ -1,7 +1,7 @@ package starknet.utils import com.swmansion.starknet.data.types.Felt -import com.swmansion.starknet.data.types.StarknetChainId +import com.swmansion.starknet.data.types.PriceUnit import com.swmansion.starknet.data.types.transactions.TransactionExecutionStatus import com.swmansion.starknet.data.types.transactions.TransactionStatus import com.swmansion.starknet.provider.Provider @@ -45,11 +45,14 @@ class DevnetClient( lateinit var defaultAccountDetails: AccountDetails - val provider: Provider by lazy { JsonRpcProvider(rpcUrl, StarknetChainId.TESTNET) } + val provider: Provider by lazy { JsonRpcProvider(rpcUrl) } private enum class TransactionVerificiationMode { RECEIPT, STATUS, DISABLED } private val transactionVerificiationMode = TransactionVerificiationMode.STATUS + private enum class StateArchiveCapacity(val value: String) { FULL("full"), NONE("none") } + private val stateArchiveCapacity = StateArchiveCapacity.FULL + companion object { // Source: https://github.com/0xSpaceShard/starknet-devnet-rs/blob/85495efb71a37ad3921c8986474b7e78a9a9f5fc/crates/starknet/src/constants.rs val accountContractClassHash = Felt.fromHex("0x4d07e40e93398ed3c76981e72dd1fd22557a78ce36c0515f679e27f0bb5bc5f") @@ -96,6 +99,9 @@ class DevnetClient( port.toString(), "--seed", seed.toString(), + // This is currently needed for devnet to support requests with specified block_id (not latest or pending) + "--state-archive-capacity", + stateArchiveCapacity.value, ) devnetProcess = devnetProcessBuilder.start() devnetProcess.waitFor(3, TimeUnit.SECONDS) @@ -127,13 +133,22 @@ class DevnetClient( } fun prefundAccountEth(accountAddress: Felt) { + prefundAccount(accountAddress, PriceUnit.WEI) + } + fun prefundAccountStrk(accountAddress: Felt) { + prefundAccount(accountAddress, PriceUnit.FRI) + } + + private fun prefundAccount(accountAddress: Felt, priceUnit: PriceUnit) { + val unit = Json.encodeToString(PriceUnit.serializer(), priceUnit) val payload = HttpService.Payload( url = mintUrl, body = """ { "address": "${accountAddress.hexString()}", - "amount": 500000000000000000000000000000 + "amount": 500000000000000000000000000000, + "unit": $unit } """.trimIndent(), method = "POST", @@ -182,6 +197,7 @@ class DevnetClient( ): DeployAccountResult { if (prefund) { prefundAccountEth(readAccountDetails(name).address) + prefundAccountStrk(readAccountDetails(name).address) } val params = listOf( diff --git a/lib/src/test/resources/contracts/src/lib.cairo b/lib/src/test/resources/contracts/src/lib.cairo index c35e85495..761b4ba9a 100644 --- a/lib/src/test/resources/contracts/src/lib.cairo +++ b/lib/src/test/resources/contracts/src/lib.cairo @@ -1,3 +1,4 @@ mod balance; mod contract_with_constructor; mod events; +mod map; diff --git a/lib/src/test/resources/contracts/src/map.cairo b/lib/src/test/resources/contracts/src/map.cairo new file mode 100644 index 000000000..50733b412 --- /dev/null +++ b/lib/src/test/resources/contracts/src/map.cairo @@ -0,0 +1,28 @@ +#[starknet::interface] +trait IMap { + // Returns the value associated with the given key. + fn get(self: @T, key: felt252) -> felt252; + // Sets the value associated with the given key. + fn put(ref self: T, key: felt252, value: felt252); +} + +#[starknet::contract] +mod Map { + use traits::Into; + + #[storage] + struct Storage { + map: LegacyMap::, + } + + #[external(v0)] + impl Map of super::IMap { + fn get(self: @ContractState, key: felt252) -> felt252 { + self.map.read(key) + } + fn put(ref self: ContractState, key: felt252, value: felt252) { + self.map.write(key, value); + } + } +} + diff --git a/lib/src/test/resources/contracts_v0/src/map.cairo b/lib/src/test/resources/contracts_v0/src/map.cairo new file mode 100644 index 000000000..87eedfe96 --- /dev/null +++ b/lib/src/test/resources/contracts_v0/src/map.cairo @@ -0,0 +1,25 @@ +// Declare this file as a StarkNet contract and set the required +// builtins. +%lang starknet +%builtins pedersen range_check + +from starkware.cairo.common.cairo_builtins import HashBuiltin + +// Define a storage variable. +@storage_var +func storage(key: felt) -> (value: felt) { +} + +@external +func put{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(key: felt, value: felt) { + storage.write(key, value); + return (); +} + +@view +func get{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(key: felt) -> ( + res: felt +) { + let (value) = storage.read(key); + return (value,); +} diff --git a/lib/starknet-jvm.md b/lib/starknet-jvm.md index 3f53eb77c..0bf5ca8a0 100644 --- a/lib/starknet-jvm.md +++ b/lib/starknet-jvm.md @@ -21,7 +21,7 @@ import com.swmansion.starknet.provider.rpc.JsonRpcProvider; public class Main { public static void main(String[] args) { // Create a provider for interacting with Starknet - Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET); + Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc"); // Create an account interface Felt accountAddress = Felt.fromHex("0x13241455"); @@ -49,7 +49,7 @@ import com.swmansion.starknet.provider.rpc.JsonRpcProvider fun main() { // Create a provider for interacting with Starknet - val provider = JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET) + val provider = JsonRpcProvider("https://example-node-url.com/rpc") // Create an account interface val accountAddress = Felt.fromHex("0x1052524524") @@ -87,7 +87,7 @@ import java.util.concurrent.CompletableFuture; public class Main { public static void main(String[] args) { // Create a provider for interacting with Starknet - Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET); + Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc"); // Create an account interface Felt accountAddress = Felt.fromHex("0x13241455"); @@ -115,7 +115,7 @@ import com.swmansion.starknet.provider.rpc.JsonRpcProvider fun main() { // Create a provider for interacting with Starknet - val provider = JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET) + val provider = JsonRpcProvider("https://example-node-url.com/rpc") // Create an account interface val accountAddress = Felt.fromHex("0x1052524524") val privateKey = Felt.fromHex("0x4232362662") @@ -152,7 +152,7 @@ import java.util.List; public class Main { public static void main(String[] args) { // Create a provider for interacting with Starknet - Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET); + Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc"); // Create an account interface Felt privateKey = Felt.fromHex("0x123"); @@ -192,7 +192,7 @@ public class Main { ```kotlin fun main(args: Array) { // Create a provider for interacting with Starknet - val provider = JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET) + val provider = JsonRpcProvider("https://example-node-url.com/rpc") // Create an account interface val privateKey = Felt.fromHex("0x123") @@ -244,7 +244,7 @@ import java.util.List; public class Main { public static void main(String[] args) { // Create a provider for interacting with Starknet - Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET); + Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc"); // Set up an account Felt privateKey = Felt.fromHex("0x123"); @@ -280,7 +280,7 @@ public class Main { ```kotlin fun main(args: Array) { // Create a provider for interacting with Starknet - val provider = JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET) + val provider = JsonRpcProvider("https://example-node-url.com/rpc") // Set up an account val privateKey = Felt.fromHex("0x123") @@ -335,7 +335,7 @@ import java.util.List; public class Main { public static void main(String[] args) { // Create a provider for interacting with Starknet - Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET); + Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc"); // Set up an account Felt privateKey = Felt.fromHex("0x123"); @@ -365,7 +365,7 @@ public class Main { ```kotlin fun main(args: Array) { // Create a provider for interacting with Starknet - val provider = JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET) + val provider = JsonRpcProvider("https://example-node-url.com/rpc") // Set up an account val privateKey = Felt.fromHex("0x123") @@ -419,7 +419,7 @@ import java.util.List; public class Main { public static void main(String[] args) { // Create a provider for interacting with Starknet - Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET); + Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc"); // Set up an account Felt privateKey = Felt.fromHex("0x1234"); @@ -458,7 +458,7 @@ public class Main { ```kotlin fun main(args: Array) { // Create a provider for interacting with Starknet - val provider = JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET) + val provider = JsonRpcProvider("https://example-node-url.com/rpc") // Set up an account val privateKey = Felt.fromHex("0x123") @@ -524,7 +524,7 @@ import java.util.List; public class Main { public static void main(String[] args) { // Create a provider for interacting with Starknet - Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET); + Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc"); // Set up an account Felt privateKey = Felt.fromHex("0x1234"); @@ -564,7 +564,7 @@ public class Main { ```kotlin fun main(args: Array) { // Create a provider for interacting with Starknet - val provider = JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET) + val provider = JsonRpcProvider("https://example-node-url.com/rpc") // Set up an account val privateKey = Felt.fromHex("0x1234") @@ -625,7 +625,7 @@ import java.util.List; public class Main { public static void main(String[] args) { - Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET); + Provider provider = new JsonRpcProvider("https://example-node-url.com/rpc"); Felt address = new Felt(0x1234); Felt privateKey = new Felt(0x1); Account account = new StandardAccount(address, privateKey, provider); @@ -814,9 +814,9 @@ to communicate with the network. ```java // JsonRpcProvider can only be created using constructor -new JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET); +new JsonRpcProvider("https://example-node-url.com/rpc"); // or with a custom HttpService -new JsonRpcProvider("https://example-node-url.com/rpc", StarknetChainId.TESTNET, myHttpService); +new JsonRpcProvider("https://example-node-url.com/rpc", myHttpService); ``` # Package com.swmansion.starknet.service.http