diff --git a/.github/workflows/cadence_lint.yml b/.github/workflows/cadence_lint.yml new file mode 100644 index 0000000..1100626 --- /dev/null +++ b/.github/workflows/cadence_lint.yml @@ -0,0 +1,51 @@ +name: Run Cadence Contract Compilation, Deployment, Transaction Execution, and Lint +on: push + +jobs: + run-cadence-lint: + runs-on: macos-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: 'true' + + - name: Install Flow CLI + run: | + brew update + brew install flow-cli + + - name: Initialize Flow + run: | + if [ ! -f flow.json ]; then + echo "Initializing Flow project..." + flow init + else + echo "Flow project already initialized." + fi + flow dependencies install + + - name: Start Flow Emulator + run: | + echo "Starting Flow emulator in the background..." + nohup flow emulator start > emulator.log 2>&1 & + sleep 5 # Wait for the emulator to start + flow project deploy --network=emulator # Deploy the recipe contracts indicated in flow.json + + - name: Run All Transactions + run: | + echo "Running all transactions in the transactions folder..." + for file in ./cadence/transactions/*.cdc; do + echo "Running transaction: $file" + TRANSACTION_OUTPUT=$(flow transactions send "$file" --signer emulator-account) + echo "$TRANSACTION_OUTPUT" + if echo "$TRANSACTION_OUTPUT" | grep -q "Transaction Error"; then + echo "Transaction Error detected in $file, failing the action..." + exit 1 + fi + done + + - name: Run Cadence Lint + run: | + echo "Running Cadence linter on .cdc files in the current repository" + flow cadence lint ./cadence/**/*.cdc diff --git a/.github/workflows/cadence_tests.yml b/.github/workflows/cadence_tests.yml new file mode 100644 index 0000000..9a51f78 --- /dev/null +++ b/.github/workflows/cadence_tests.yml @@ -0,0 +1,34 @@ +name: Run Cadence Tests +on: push + +jobs: + run-cadence-tests: + runs-on: macos-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: 'true' + + - name: Install Flow CLI + run: | + brew update + brew install flow-cli + + - name: Initialize Flow + run: | + if [ ! -f flow.json ]; then + echo "Initializing Flow project..." + flow init + else + echo "Flow project already initialized." + fi + + - name: Run Cadence Tests + run: | + if test -f "cadence/tests.cdc"; then + echo "Running Cadence tests in the current repository" + flow test cadence/tests.cdc + else + echo "No Cadence tests found. Skipping tests." + fi diff --git a/.gitignore b/.gitignore index 496ee2c..b1d92af 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -.DS_Store \ No newline at end of file +.DS_Store +/imports/ +/.idea/ \ No newline at end of file diff --git a/README.md b/README.md index 90cc7f3..29bdcb5 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ When you want to give someone else access to the admin resource. - [Description](#description) - [What is included in this repository?](#what-is-included-in-this-repository) - [Supported Recipe Data](#recipe-data) +- [Deploying Recipe Contracts and Running Transactions Locally (Flow Emulator)](#deploying-recipe-contracts-and-running-transactions-locally-flow-emulator) - [License](#license) ## Description @@ -19,7 +20,6 @@ The Cadence Cookbook is a collection of code examples, recipes, and tutorials de Each recipe in the Cadence Cookbook is a practical coding example that showcases a specific aspect of Cadence or use-case on Flow, including smart contract development, interaction, and best practices. By following these recipes, you can gain hands-on experience and learn how to leverage Cadence for your blockchain projects. - ### Contributing to the Cadence Cookbook Learn more about the contribution process [here](https://github.com/onflow/cadence-cookbook/blob/main/contribute.md). @@ -34,17 +34,17 @@ Recipe metadata, such as title, author, and category labels, is stored in `index ``` recipe-name/ -├── cadence/ # Cadence files for recipe examples -│ ├── contract.cdc # Contract code -│ ├── transaction.cdc # Transaction code -│ ├── tests.cdc # Tests code -├── explanations/ # Explanation files for recipe examples -│ ├── contract.txt # Contract code explanation -│ ├── transaction.txt # Transaction code explanation -│ ├── tests.txt # Tests code explanation -├── index.js # Root file for storing recipe metadata -├── README.md # This README file -└── LICENSE # License information +├── cadence/ # Cadence files for recipe examples +│ ├── contracts/Recipe.cdc # Contract code +│ ├── transactions/add_admin_resource.cdc # Transaction code +│ ├── tests/Recipe_test.cdc # Tests code +├── explanations/ # Explanation files for recipe examples +│ ├── contract.txt # Contract code explanation +│ ├── transaction.txt # Transaction code explanation +│ ├── tests.txt # Tests code explanation +├── index.js # Root file for storing recipe metadata +├── README.md # This README file +└── LICENSE # License information ``` ## Supported Recipe Data @@ -95,6 +95,43 @@ export const sampleRecipe= { transactionExplanation: transactionExplanationPath, }; ``` +## Deploying Recipe Contracts and Running Transactions Locally (Flow Emulator) + +This section explains how to deploy the recipe's contracts to the Flow emulator, run the associated transaction with sample arguments, and verify the results. + +### Prerequisites + +Before deploying and running the recipe: + +1. Install the Flow CLI. You can find installation instructions [here](https://docs.onflow.org/flow-cli/install/). +2. Ensure the Flow emulator is installed and ready to use with `flow version`. + +### Step 1: Start the Flow Emulator + +Start the Flow emulator to simulate the blockchain environment locally + +```bash +flow emulator start +``` + +### Step 2: Install Dependencies and Deploy Project Contracts + +Deploy contracts to the emulator. This will deploy all the contracts specified in the _deployments_ section of `flow.json` whether project contracts or dependencies. + +```bash +flow dependencies install +flow project deploy --network=emulator +``` + +### Step 3: Run the Transaction + +Transactions associated with the recipe are located in `./cadence/transactions`. To run a transaction, execute the following command: + +```bash +flow transactions send cadence/transactions/TRANSACTION_NAME.cdc --signer emulator-account +``` + +To verify the transaction's execution, check the emulator logs printed during the transaction for confirmation messages. You can add the `--log-level debug` flag to your Flow CLI command for more detailed output during contract deployment or transaction execution. ## License diff --git a/cadence/contract.cdc b/cadence/contract.cdc deleted file mode 100644 index b85f72a..0000000 --- a/cadence/contract.cdc +++ /dev/null @@ -1,13 +0,0 @@ -// Admin is a special authorization resource that -// allows the owner to perform important NFT -// functions -// -pub resource Admin { - -..... - - pub fun createNewAdmin(): @Admin { - return <-create Admin() - } - -} \ No newline at end of file diff --git a/cadence/contract.cdc b/cadence/contract.cdc new file mode 120000 index 0000000..b64184f --- /dev/null +++ b/cadence/contract.cdc @@ -0,0 +1 @@ +./cadence/contracts/Recipe.cdc \ No newline at end of file diff --git a/cadence/contracts/Recipe.cdc b/cadence/contracts/Recipe.cdc new file mode 100644 index 0000000..1091afb --- /dev/null +++ b/cadence/contracts/Recipe.cdc @@ -0,0 +1,13 @@ +access(all) contract Recipe { + // Admin is a special authorization resource that + // allows the owner to perform important NFT + // functions + // + access(all) resource Admin { + + access(all) fun createNewAdmin(): @Admin { + return <-create Admin() + } + + } +} \ No newline at end of file diff --git a/cadence/tests/Recipe_test.cdc b/cadence/tests/Recipe_test.cdc new file mode 100644 index 0000000..e5fbaed --- /dev/null +++ b/cadence/tests/Recipe_test.cdc @@ -0,0 +1,19 @@ +import Test + +access(all) let account = Test.getAccount(0x0000000000000007) + +access(all) +fun setup() { + let err = Test.deployContract( + name: "Recipe", + path: "../contracts/Recipe.cdc", + arguments: [], + ) + + Test.expect(err, Test.beNil()) +} + +access(all) fun testExample() { + let array = [1, 2, 3] + Test.expect(array.length, Test.equal(3)) +} diff --git a/cadence/transaction.cdc b/cadence/transaction.cdc deleted file mode 100644 index d4f203d..0000000 --- a/cadence/transaction.cdc +++ /dev/null @@ -1,19 +0,0 @@ -import SetAndSeries from 0x01 - -transaction { - -let adminCheck: &SetAndSeries.Admin - - prepare(acct: AuthAccount, acct2: AuthAccount) { - self.adminCheck = acct.borrow<&SetAndSeries.Admin>(from: SetAndSeries.AdminStoragePath) - ?? panic("could not borrow admin reference") - - - acct2.save(<- self.adminCheck.createNewAdmin(), to: SetAndSeries.AdminStoragePath) - - } - - execute { - log("New Admin Resource Created") - } -} diff --git a/cadence/transaction.cdc b/cadence/transaction.cdc new file mode 120000 index 0000000..daea46c --- /dev/null +++ b/cadence/transaction.cdc @@ -0,0 +1 @@ +./cadence/transactions/add_admin_resource.cdc \ No newline at end of file diff --git a/cadence/transactions/add_admin_resource.cdc b/cadence/transactions/add_admin_resource.cdc new file mode 100644 index 0000000..4f84105 --- /dev/null +++ b/cadence/transactions/add_admin_resource.cdc @@ -0,0 +1,21 @@ +import "SetAndSeries" + +transaction { + + prepare(signer: auth(Storage) &Account) { + let acct = signer.storage.borrow<&SetAndSeries>(from: /storage/myCollection) + ?? panic("Failed to borrow reference to collection") + + let result1 = acct.performOperation() + log(result1) + + let acct2 = signer.storage.borrow<&SetAndSeries>(from: /storage/anotherCollection) + ?? panic("Failed to borrow reference to another collection") + let result2 = acct2.performAnotherOperation() + log(result2) + } + + execute { + log("New Admin Resource Created") + } +} diff --git a/emulator-account.pkey b/emulator-account.pkey new file mode 100644 index 0000000..75611bd --- /dev/null +++ b/emulator-account.pkey @@ -0,0 +1 @@ +0xdc07d83a937644ff362b279501b7f7a3735ac91a0f3647147acf649dda804e28 \ No newline at end of file diff --git a/explanations/contract.txt b/explanations/contract.txt index 8522e18..b58411b 100644 --- a/explanations/contract.txt +++ b/explanations/contract.txt @@ -1 +1,5 @@ -This code is used to create a new Admin resource which can then be saved to another users account +The Recipe contract is designed to manage administrative permissions using a special resource called Admin. This resource gives its owner the ability to perform important NFT-related actions in a secure and controlled way. + +The Admin resource includes a function called createNewAdmin. This function allows the creation of new Admin resources, which can be given to other users. These users can then store the Admin resource in their account and gain administrative permissions. + +By keeping these permissions within the Admin resource, the contract ensures that critical operations are carefully managed. This makes the system secure and flexible, especially useful for NFT platforms or other applications that need clear and safe access controls. \ No newline at end of file diff --git a/explanations/transaction.txt b/explanations/transaction.txt index 66a29da..fec1707 100644 --- a/explanations/transaction.txt +++ b/explanations/transaction.txt @@ -1 +1,5 @@ -Before executing this transaction you first need to borrow the Admin resource from the 'acct'. Once that is borrowed, you then take 'acct2' and save the resource that is returned when you call the createNewAdmin() funtion to your storage path. \ No newline at end of file +Before running this transaction, you need to borrow the Admin resource from the account's storage. This is done by accessing the SetAndSeries resource stored at /storage/myCollection. If the resource is not found, the transaction will stop and show an error. + +Once the resource is borrowed, the performOperation function is called on it, and the result is logged. Next, the transaction borrows another SetAndSeries resource from /storage/anotherCollection. If this resource cannot be found, the transaction will error out as well. After successfully borrowing it, the performAnotherOperation function is called, and its result is also logged. + +In the final step, the transaction logs a message confirming that a new Admin resource has been created. This ensures the transaction is complete and provides a clear record of its success. \ No newline at end of file diff --git a/flow.json b/flow.json new file mode 100644 index 0000000..5b1441c --- /dev/null +++ b/flow.json @@ -0,0 +1,33 @@ +{ + "contracts": { + "Recipe": { + "source": "cadence/contracts/Recipe.cdc", + "aliases": { + "emulator": "f8d6e0586b0a20c7", + "testing": "0000000000000007" + } + } + }, + "networks": { + "emulator": "127.0.0.1:3569", + "mainnet": "access.mainnet.nodes.onflow.org:9000", + "testing": "127.0.0.1:3569", + "testnet": "access.devnet.nodes.onflow.org:9000" + }, + "accounts": { + "emulator-account": { + "address": "f8d6e0586b0a20c7", + "key": { + "type": "file", + "location": "emulator-account.pkey" + } + } + }, + "deployments": { + "emulator": { + "emulator-account": [ + "Recipe" + ] + } + } +} \ No newline at end of file diff --git a/index.js b/index.js index a81d8d4..cfd883c 100644 --- a/index.js +++ b/index.js @@ -9,21 +9,19 @@ const transactionPath = `${recipe}/cadence/transaction.cdc`; const smartContractExplanationPath = `${recipe}/explanations/contract.txt`; const transactionExplanationPath = `${recipe}/explanations/transaction.txt`; -export const addAdminResourceToAccount= { +export const addAdminResourceToAccount = { slug: recipe, title: "Add Admin Resource to Account", createdAt: new Date(2022, 3, 1), author: "Flow Blockchain", playgroundLink: "https://play.onflow.org/a7d190b6-e0f1-4acc-b34c-f37b39fbab33?type=tx&id=1e1128cf-b88e-4f10-9877-247b71a62ee4&storage=none", - excerpt: - "When you want to give someone else access to the admin resource.", + excerpt: "When you want to give someone else access to the admin resource.", smartContractCode: contractPath, smartContractExplanation: smartContractExplanationPath, transactionCode: transactionPath, transactionExplanation: transactionExplanationPath, filters: { - difficulty: "intermediate" - } + difficulty: "intermediate", + }, }; -