From ba44d3a4f4442774105b292c1c3c2c945110ff06 Mon Sep 17 00:00:00 2001 From: "Omar U. Espejel" Date: Tue, 17 Oct 2023 13:19:18 +0700 Subject: [PATCH] :memo: update script subchapter --- src/SUMMARY.md | 1 + src/ch02-12-01-deployment-script.md | 176 ++++++++++++++++++++++++++++ src/ch02-12-foundry-cast.md | 159 ------------------------- 3 files changed, 177 insertions(+), 159 deletions(-) create mode 100644 src/ch02-12-01-deployment-script.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 3c7ef4a5b..e9fbb84f7 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -26,6 +26,7 @@ - [Starknet-rs: Rust SDK 🚧](ch02-10-starknet-rs.md) - [Foundry Forge: Testing 🚧](ch02-11-foundry-forge.md) - [Foundry Cast: Interacting with Starknet](ch02-12-foundry-cast.md) + - [Example - Deployment Script](ch02-12-01-deployment-script.md) ## Architecture diff --git a/src/ch02-12-01-deployment-script.md b/src/ch02-12-01-deployment-script.md new file mode 100644 index 000000000..817ff4f8b --- /dev/null +++ b/src/ch02-12-01-deployment-script.md @@ -0,0 +1,176 @@ +# Deployment Script Example + +This tutorial explains how to set up a test and deployment environment for smart contracts. The given script initializes accounts, runs tests, and carries out multicalls. + +Disclaimer: This is an example. Use it as a foundation for your own work, adjusting as needed. + +## Setup + +### 1. Prepare the Script File + +- In your project's root folder, create a file named **`script.sh`**. This will house the script. +- Adjust permissions to make the file executable: + +```sh +chmod +x script.sh +``` + +### 2. Insert the Script + +Below is the content for `script.sh`. It adheres to best practices for clarity, error management, and long-term support. + +**Security Note**: Using environment variables is safer than hardcoding private keys in your scripts, but they're still accessible to any process on your machine and could potentially be leaked in logs or error messages. + +```sh +#!/usr/bin/env bash + +# Ensure the script stops on first error +set -e + +# Global variables +file_path="$HOME/.starknet_accounts/starknet_open_zeppelin_accounts.json" +CONTRACT_NAME="HelloStarknet" +PROFILE_NAME="account1" +MULTICALL_FILE="multicall.toml" +FAILED_TESTS=false + +# Addresses and Private keys as environment variables +ACCOUNT1_ADDRESS=${ACCOUNT1_ADDRESS:-"0x7f61fa3893ad0637b2ff76fed23ebbb91835aacd4f743c2347716f856438429"} +ACCOUNT2_ADDRESS=${ACCOUNT2_ADDRESS:-"0x53c615080d35defd55569488bc48c1a91d82f2d2ce6199463e095b4a4ead551"} +ACCOUNT1_PRIVATE_KEY=${ACCOUNT1_PRIVATE_KEY:-"CHANGE_ME"} +ACCOUNT2_PRIVATE_KEY=${ACCOUNT2_PRIVATE_KEY:-"CHANGE_ME"} + +# Utility function to log messages +function log_message() { + echo -e "\n$1" +} + +# Step 1: Clean previous environment +if [ -e "$file_path" ]; then + log_message "Removing existing accounts file..." + rm -rf "$file_path" +fi + +# Step 2: Define accounts for the smart contract +accounts_json=$(cat <&1) +if echo "$testing_result" | grep -q "Failure"; then + echo -e "Tests failed!\n" + snforge + echo -e "\nEnsure that your tests are passing before proceeding.\n" + FAILED_TESTS=true +fi + +if [ "$FAILED_TESTS" != "true" ]; then + echo "Tests passed successfully." + + # Step 4: Create new account(s) + echo -e "\nCreating account(s)..." + for row in $(echo "${accounts_json}" | jq -c '.[]'); do + name=$(echo "${row}" | jq -r '.name') + address=$(echo "${row}" | jq -r '.address') + private_key=$(echo "${row}" | jq -r '.private_key') + + account_creation_result=$(sncast --url http://localhost:5050/rpc account add --name "$name" --address "$address" --private-key "$private_key" --add-profile 2>&1) + if echo "$account_creation_result" | grep -q "error:"; then + echo "Account $name already exists." + else + echo "Account $name created successfully." + fi + done + + # Step 5: Build, declare, and deploy the contract + echo -e "\nBuilding the contract..." + scarb build + + echo -e "\nDeclaring the contract..." + declaration_output=$(sncast --profile "$PROFILE_NAME" --wait declare --contract-name "$CONTRACT_NAME" 2>&1) + + if echo "$declaration_output" | grep -q "error: Class with hash"; then + echo "Class hash already declared." + CLASS_HASH=$(echo "$declaration_output" | sed -n 's/.*Class with hash \([^ ]*\).*/\1/p') + else + echo "New class hash declaration." + CLASS_HASH=$(echo "$declaration_output" | grep -o 'class_hash: 0x[^ ]*' | sed 's/class_hash: //') + fi + + echo "Class Hash: $CLASS_HASH" + + echo -e "\nDeploying the contract..." + deployment_result=$(sncast --profile "$PROFILE_NAME" deploy --class-hash "$CLASS_HASH") + CONTRACT_ADDRESS=$(echo "$deployment_result" | grep -o "contract_address: 0x[^ ]*" | awk '{print $2}') + echo "Contract address: $CONTRACT_ADDRESS" + + # Step 6: Create and execute multicalls + echo -e "\nSetting up multicall..." + cat >"$MULTICALL_FILE" <<-EOM +[[call]] +call_type = 'invoke' +contract_address = '$CONTRACT_ADDRESS' +function = 'increase_balance' +inputs = ['0x1'] + +[[call]] +call_type = 'invoke' +contract_address = '$CONTRACT_ADDRESS' +function = 'increase_balance' +inputs = ['0x2'] +EOM + + echo "Executing multicall..." + sncast --profile "$PROFILE_NAME" multicall run --path "$MULTICALL_FILE" + + # Step 7: Query the contract state + echo -e "\nChecking balance..." + sncast --profile "$PROFILE_NAME" call --contract-address "$CONTRACT_ADDRESS" --function get_balance + + # Step 8: Clean up temporary files + echo -e "\nCleaning up..." + [ -e "$MULTICALL_FILE" ] && rm "$MULTICALL_FILE" + + echo -e "\nScript completed successfully.\n" +fi +``` + +### 3. Adjust the Bash Path + +The line `#!/usr/bin/env bash` indicates the path to the bash interpreter. If you require a different version or location of bash, determine its path using: + +```sh +which bash +``` + +Then replace `#!/usr/bin/env` bash in the script with the resulting path, such as `#!/path/to/your/bash`. + +## Execution + +When running the script, you'll need to provide the environment variables `ACCOUNT1_PRIVATE_KEY` and `ACCOUNT2_PRIVATE_KEY`. + +Example: + +```sh +ACCOUNT1_PRIVATE_KEY="0x259f4329e6f4590b" ACCOUNT2_PRIVATE_KEY="0xb4862b21fb97d" ./script.sh +``` + +## Considerations + +- The **`set -e`** directive in the script ensures it exits if any command fails, enhancing the reliability of the deployment and testing process. +- Always secure private keys and sensitive information. Keep them away from logs and visible outputs. +- For greater flexibility, consider moving hardcoded values like accounts or contract names to a configuration file. This approach simplifies updates and overall management. \ No newline at end of file diff --git a/src/ch02-12-foundry-cast.md b/src/ch02-12-foundry-cast.md index 7f4e2daa8..5be1fa3a8 100644 --- a/src/ch02-12-foundry-cast.md +++ b/src/ch02-12-foundry-cast.md @@ -502,162 +502,3 @@ The expected balance, `0x9`, is confirmed. ## Conclusion This guide detailed the use of `sncast`, a robust command-line tool tailored for starknet smart contracts. Its purpose is to make interactions with starknet's smart contracts effortless. Key functionalities include contract deployment, function invocation, and function calling. - -## SNCAST SCRIPT - -In light of the above documentation, we have also added a script code you can modify and use to your benefit. - -1. Create a `script.sh` file in the root folder of your project. -2. Give proper file permissions to the file - -```sh -chmod +x script.sh -``` - -3. Paste this into the file. - -```sh -#!/usr/bin/bash - -# First, lets delete the open zeppelin accounts json file -file_path="$HOME/.starknet_accounts/starknet_open_zeppelin_accounts.json" -rm -rf $file_path - -# An array of accounts you want to add -accounts_json=$( - cat <&1) -if echo "$testing_result" | grep -q "Failure"; then - echo "Tests failed to pass!!!" - echo "" - snforge - echo " " - echo "Make sure your tests are passing" - echo " " - FAILED_TESTS=true -fi - -if [ "$FAILED_TESTS" != "true" ]; then - echo "Tests passed!!!" - echo " " - echo "Creating account(s)" - - # Step 2: Add a new account(s) - for row in $(echo "${accounts_json}" | jq -c '.[]'); do - # Extract values from JSON - name=$(echo "${row}" | jq -r '.name') - address=$(echo "${row}" | jq -r '.address') - private_key=$(echo "${row}" | jq -r '.private_key') - # Call the sncast command for each account - account_creation_result=$(sncast --url http://localhost:5050/rpc account add --name "$name" --address "$address" --private-key "$private_key" --add-profile 2>&1) - if echo "$account_creation_result" | grep -q "error:"; then - echo "Account $name already exists" - else - echo "Account: $name created successfully." - fi - done - - # Step 3: Build the contract - echo " " - echo "Building the contract" - scarb build - - # Step 4: Declare the contract - echo " " - echo "Declaring the contract..." - declaration_output=$(sncast --profile $PROFILE_NAME --wait declare --contract-name $CONTRACT_NAME 2>&1) - if echo "$declaration_output" | grep -q "error: Class with hash"; then - echo "Class hash already declared" - class_hash=$(echo "$declaration_output" | sed -n 's/.*Class with hash \([^ ]*\).*/\1/p') - CLASS_HASH=$class_hash - else - echo "New class hash declaration" - class_hash=$(echo "$declaration_output" | grep -o 'class_hash: 0x[^ ]*' | sed 's/class_hash: //') - CLASS_HASH=$class_hash - fi - - echo "Class Hash: $CLASS_HASH" - - # Step 5: Deploy the contract - echo " " - echo "Deploying the contract..." - deployment_result=$(sncast --profile $PROFILE_NAME deploy --class-hash "$CLASS_HASH") - CONTRACT_ADDRESS=$(echo "$deployment_result" | grep -o "contract_address: 0x[^ ]*" | awk '{print $2}') - echo "Contract address: $CONTRACT_ADDRESS" - - # Step 6: Perform a multicall - echo " " - echo "Performing a multicall..." - - # Create a multicall .toml file and add some calls there. - MULTICALL_FILE="multicall.toml" - echo "[[call]]" >"$MULTICALL_FILE" - echo "call_type = 'invoke'" >>"$MULTICALL_FILE" - echo "contract_address = '$CONTRACT_ADDRESS'" >>"$MULTICALL_FILE" - echo "function = 'increase_balance'" >>"$MULTICALL_FILE" - echo "inputs = ['0x1']" >>"$MULTICALL_FILE" - - # Create some space between the two calls - echo " " >>"$MULTICALL_FILE" - - echo "[[call]]" >>"$MULTICALL_FILE" - echo "call_type = 'invoke'" >>"$MULTICALL_FILE" - echo "contract_address = '$CONTRACT_ADDRESS'" >>"$MULTICALL_FILE" - echo "function = 'increase_balance'" >>"$MULTICALL_FILE" - echo "inputs = ['0x2']" >>"$MULTICALL_FILE" - - # Run the multicall - sncast --profile $PROFILE_NAME multicall run --path "$MULTICALL_FILE" - - echo " " - - echo "Checking balance" - sncast --profile $PROFILE_NAME call --contract-address $CONTRACT_ADDRESS --function get_balance - echo " " - - # Step 7: Clean up - # Clean up the multicall file by deleting it - [ -e "$MULTICALL_FILE" ] && rm "$MULTICALL_FILE" - - echo "Script completed successfully" - echo " " -fi - -``` - -4. Update the entry point of the script that is the first line by your bash location. To get bash location run and update the line accordingly. - -```sh -which bash -``` - -5. Update the `CONTRACT_NAME` to your contract name - -6. Run the file - -```sh -./script.sh -```