From 61609ea26d49ea8cc6e50e780450667211bd6dad Mon Sep 17 00:00:00 2001 From: Chris Anatalio Date: Mon, 1 Dec 2025 13:45:13 +0800 Subject: [PATCH 1/9] Update sidebar and create md file from template --- tutorials/sidebar.js | 1 + .../writing-your-first-smart-contract.md | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tutorials/writing-your-first-smart-contract.md diff --git a/tutorials/sidebar.js b/tutorials/sidebar.js index f17d4ad243..e65967778a 100644 --- a/tutorials/sidebar.js +++ b/tutorials/sidebar.js @@ -1,6 +1,7 @@ module.exports = { tutorials: [ 'overview', + 'writing-your-first-smart-contract', { type: 'category', label: 'Frontend Development', diff --git a/tutorials/writing-your-first-smart-contract.md b/tutorials/writing-your-first-smart-contract.md new file mode 100644 index 0000000000..ae5a4c97f0 --- /dev/null +++ b/tutorials/writing-your-first-smart-contract.md @@ -0,0 +1,28 @@ +--- +title: Writing Your First Smart Contract +sidebar_position: 2 +--- + +*Feel free to add more sections or adjust as needed for your tutorial!* + +--- +### Writing Your First Smart Contract + +Step-by-step instructions on creating a simple ink! contract, explaining key concepts like storage and messages. + +### Prerequisites + +What should the reader know or have before starting? + +### Body + +Describe the first step. Include code, explanations, or images as needed. +Describe the next step. Add more steps as needed. + +### Conclusion + +Summarize the key takeaways from the tutorial. Suggest next steps, further reading, or related tutorials. + +### Author _(optional)_ + +Write a short bio and link to your profile, blog, or project. From bc1e330f641dd5c49b7a22e44fd4f785a73453c9 Mon Sep 17 00:00:00 2001 From: Chris Anatalio Date: Mon, 1 Dec 2025 17:26:31 +0800 Subject: [PATCH 2/9] Building out content and overall article structure --- .../writing-your-first-smart-contract.md | 230 +++++++++++++++++- 1 file changed, 221 insertions(+), 9 deletions(-) diff --git a/tutorials/writing-your-first-smart-contract.md b/tutorials/writing-your-first-smart-contract.md index ae5a4c97f0..05aea266b1 100644 --- a/tutorials/writing-your-first-smart-contract.md +++ b/tutorials/writing-your-first-smart-contract.md @@ -3,26 +3,238 @@ title: Writing Your First Smart Contract sidebar_position: 2 --- -*Feel free to add more sections or adjust as needed for your tutorial!* - --- -### Writing Your First Smart Contract -Step-by-step instructions on creating a simple ink! contract, explaining key concepts like storage and messages. +### Overview + +We will walk through hand-on instructions to create a +fully functional [ink!](https://use.ink/docs/v6) smart contract. + +**We will break down and explain key concepts including:** + +- Storage: Reading, Writing & Mutating Storage +- Messages + +:::note +**Learning Objectives:** + +⭐️ _By the end of this tutorial, you will be able to write, compile, build, test and deploy an ink! smart contract._ + +⭐️ _You will be familiar with all the important components of a Rust ink! smart contract._ + +⭐️ _You will understand how to use the Pop CLI to work with ink! smart contracts._ + +⭐️ _You will understand important concepts like storage, events and how to use them in your smart contract._ +::: ### Prerequisites -What should the reader know or have before starting? +_Here's what you'll need to get started:_ + +- Install Brew: https://brew.sh/ +- Install [Rust](https://rust-lang.org/tools/install/), [Cargo](https://doc.rust-lang.org/cargo/) + and [Pop CLI](https://github.com/r0gue-io/pop-cli): https://use.ink/docs/v6/getting-started/setup +- Read up on the Pop CLI basics: https://learn.onpop.io/ + +After installing the prerequisites, verify that they are installed correctly: + +**Verify Rust install:** + +```bash +rustc --version +``` + +**Verify Cargo install:** + +```bash +cargo --version +``` + +**Verify Pop CLI install:** + +```bash +pop --version +``` + +---- + +### Creating a New Project + +:::note +**Display available Pop CLI commands:** + +_If you need help with any of the commands below, run:_ + +```bash +pop --help +``` + +::: + +First, let's create a new project using the `pop new` command: + +**Create a new project:** + +- Pass in `contract` to the command `pop new` +- We name the contract`helloink` +- Finally, we use the [Standard Template](https://github.com/use-ink/ink-examples/tree/main/flipper), + passing in + `-t standard`: +- Check out + the [Pop CLI docs](https://learn.onpop.io/contracts/guides/create-a-new-contract) for more options + +```bash +pop new contract helloink -t standard +``` + +Next, let's review the files that were created: + +**View files:** + +```bash +cd helloink +ls -latr +``` + +:::note + +⚠️ **This code is provided for educational purposes only.** + +Contracts should **ALWAYS** be formally audited and reviewed for security vulnerabilities before being deployed to +mainnet. + +Consult the source repository at https://github.com/use-ink/ink-examples/tree/main/flipper to review the +template code. + +::: + +**You will see the following files:** + +- `Cargo.toml` - The [cargo project manifest file](https://doc.rust-lang.org/cargo/reference/manifest.html) +- `lib.rs` - The [main source file](https://github.com/use-ink/ink-examples/blob/main/flipper/lib.rs) for the smart + contract written in Rust +- `.gitignore`- A file that tells git which files and directories to ignore + +Import the project into your IDE and let's dig in! + +--- + +### Reviewing the Generated Smart Contract + +Let's review each major component of the `lib.rs` file: + +**Conditional Compilation Statement** + +Configures [Conditional compilation](https://doc.rust-lang.org/reference/conditional-compilation.html) to +ensure an optimal memory footprint and performance. + +- The `no_main` attribute is required to compile the contract for on-chain execution. +- The `no_std` ensures the standard library is not included in the contract + - The [Rust standard library](https://doc.rust-lang.org/std/) is OS-dependent and too heavyweight for on-chain use + - More details on [no_std](https://docs.rust-embedded.org/book/intro/no-std.html) + +```rust +#![cfg_attr(not(feature = "std"), no_std, no_main)] +``` + +:::note +Check out +the [FAQ](https://use.ink/docs/v6/faq/#what-does-the-cfg_attrnotfeature--std-no_std-no_main-at-the-beginning-of-each-contract-mean) +for a more in-depth explanation. +::: + +**Module Declaration** + +Next let's review the module declaration: + +Applies the `#[ink::contract]` [proc macro attribute]((https://doc.rust-lang.org/reference/procedural-macros.html)) to +the module declaration. + +- Marks the module as an ink! contract + and [checks for invalid arguments and structure](https://use.ink/docs/v6/macros-attributes/contract#analysis). +- Uses your provided contract code to generate valid, optimized code for execution + on-chain. +- This allows you to simply define your contract's storage and other functionality + without writing a bunch of complicated, boilerplate code! 😊 + +```rust +#[ink::contract] +mod helloink {} +``` + +**Every ink! Smart Contract MUST have:** + +- EXACTLY one `#[ink(storage)]` struct +- AT LEAST one `#[ink(constructor)]` function +- AT LEAST one `#[ink(message)]` function + +:::note +Learn more about the [ink::contract macro](https://use.ink/docs/v6/macros-attributes/contract) +::: + +**Storage Declaration** + +```rust + #[ink(storage)] + pub struct Helloink { + /// Stores a single `bool` value on the storage. + value: bool, + } +``` + +**Constructor and Message Declaration** + +```rust + impl Helloink { + #[ink(constructor)] + pub fn new(init_value: bool) -> Self { + Self { value: init_value } + } + + #[ink(message)] + pub fn flip(&mut self) { + self.value = !self.value; + } + + #[ink(message)] + pub fn get(&self) -> bool { + self.value + } + } +``` + +---- + +### Executing Tests + +**Run tests:** + +```bash + +``` + +### Deploy to Testnet + +**Deploy to testnet:** + +```bash + +``` + +---- + +### Customizing the Code + +```rust -### Body +``` -Describe the first step. Include code, explanations, or images as needed. -Describe the next step. Add more steps as needed. +---- ### Conclusion Summarize the key takeaways from the tutorial. Suggest next steps, further reading, or related tutorials. -### Author _(optional)_ +### Author Write a short bio and link to your profile, blog, or project. From 462894f92f9bbe3266d87bd217f2e7237edab8d5 Mon Sep 17 00:00:00 2001 From: Chris Anatalio Date: Mon, 1 Dec 2025 23:32:18 +0800 Subject: [PATCH 3/9] Update and cleanup content and code samples --- .../writing-your-first-smart-contract.md | 130 +++++++++++++----- 1 file changed, 96 insertions(+), 34 deletions(-) diff --git a/tutorials/writing-your-first-smart-contract.md b/tutorials/writing-your-first-smart-contract.md index 05aea266b1..0d4930289c 100644 --- a/tutorials/writing-your-first-smart-contract.md +++ b/tutorials/writing-your-first-smart-contract.md @@ -10,19 +10,24 @@ sidebar_position: 2 We will walk through hand-on instructions to create a fully functional [ink!](https://use.ink/docs/v6) smart contract. +Follow along with the companion GitHub repo [helloink](https://github.com/anataliocs/helloink). + **We will break down and explain key concepts including:** +- Using the Pop CLI - Storage: Reading, Writing & Mutating Storage +- Constructors - Messages +- Ink contract macros :::note **Learning Objectives:** -⭐️ _By the end of this tutorial, you will be able to write, compile, build, test and deploy an ink! smart contract._ +⭐️ _By the end of this tutorial, you will be able to write, compile, build, test and deploy **ink!** contracts._ -⭐️ _You will be familiar with all the important components of a Rust ink! smart contract._ +⭐️ _You will be familiar with all the key components of **ink!** smart contract._ -⭐️ _You will understand how to use the Pop CLI to work with ink! smart contracts._ +⭐️ _You will understand how to use the Pop CLI._ ⭐️ _You will understand important concepts like storage, events and how to use them in your smart contract._ ::: @@ -33,24 +38,24 @@ _Here's what you'll need to get started:_ - Install Brew: https://brew.sh/ - Install [Rust](https://rust-lang.org/tools/install/), [Cargo](https://doc.rust-lang.org/cargo/) - and [Pop CLI](https://github.com/r0gue-io/pop-cli): https://use.ink/docs/v6/getting-started/setup -- Read up on the Pop CLI basics: https://learn.onpop.io/ + and [Pop CLI](https://github.com/r0gue-io/pop-cli): https://use.ink/docs/v6/getting-started/setup +- Read up on the [Pop CLI](https://learn.onpop.io/) -After installing the prerequisites, verify that they are installed correctly: +_After that, let's verify everything is installed correctly:_ -**Verify Rust install:** +**Verify Rust version:** ```bash rustc --version ``` -**Verify Cargo install:** +**Verify Cargo version:** ```bash cargo --version ``` -**Verify Pop CLI install:** +**Verify Pop CLI version:** ```bash pop --version @@ -58,7 +63,7 @@ pop --version ---- -### Creating a New Project +### Create a New Project with the Pop CLI :::note **Display available Pop CLI commands:** @@ -71,23 +76,21 @@ pop --help ::: -First, let's create a new project using the `pop new` command: +_First, let's create a new project using the `pop new` command:_ **Create a new project:** - Pass in `contract` to the command `pop new` - We name the contract`helloink` -- Finally, we use the [Standard Template](https://github.com/use-ink/ink-examples/tree/main/flipper), - passing in - `-t standard`: -- Check out - the [Pop CLI docs](https://learn.onpop.io/contracts/guides/create-a-new-contract) for more options +- Lastly, we use the [Standard Template](https://github.com/use-ink/ink-examples/tree/main/flipper), + passing in `-t standard` +- Check out the [Pop CLI docs](https://learn.onpop.io/contracts/guides/create-a-new-contract) for more options ```bash pop new contract helloink -t standard ``` -Next, let's review the files that were created: +_Next, let's review the files that were generated:_ **View files:** @@ -98,30 +101,29 @@ ls -latr :::note -⚠️ **This code is provided for educational purposes only.** +⚠️ **This code is provided for educational purposes.** Contracts should **ALWAYS** be formally audited and reviewed for security vulnerabilities before being deployed to mainnet. -Consult the source repository at https://github.com/use-ink/ink-examples/tree/main/flipper to review the -template code. +Review the source repository at https://github.com/use-ink/ink-examples/tree/main/flipper ::: -**You will see the following files:** +**Generated files:** - `Cargo.toml` - The [cargo project manifest file](https://doc.rust-lang.org/cargo/reference/manifest.html) - `lib.rs` - The [main source file](https://github.com/use-ink/ink-examples/blob/main/flipper/lib.rs) for the smart contract written in Rust -- `.gitignore`- A file that tells git which files and directories to ignore +- `.gitignore`- Tells git files/directories to ignore -Import the project into your IDE and let's dig in! +_Import the project into your IDE and let's dig in!_ --- ### Reviewing the Generated Smart Contract -Let's review each major component of the `lib.rs` file: +_Let's review each major component of the `lib.rs` file:_ **Conditional Compilation Statement** @@ -129,7 +131,7 @@ Configures [Conditional compilation](https://doc.rust-lang.org/reference/conditi ensure an optimal memory footprint and performance. - The `no_main` attribute is required to compile the contract for on-chain execution. -- The `no_std` ensures the standard library is not included in the contract +- The `no_std` ensures the standard library is not included in the contract. - The [Rust standard library](https://doc.rust-lang.org/std/) is OS-dependent and too heavyweight for on-chain use - More details on [no_std](https://docs.rust-embedded.org/book/intro/no-std.html) @@ -145,12 +147,12 @@ for a more in-depth explanation. **Module Declaration** -Next let's review the module declaration: +_Next, let's take a look at the module declaration:_ Applies the `#[ink::contract]` [proc macro attribute]((https://doc.rust-lang.org/reference/procedural-macros.html)) to the module declaration. -- Marks the module as an ink! contract +- Marks the module as an **ink!** contract and [checks for invalid arguments and structure](https://use.ink/docs/v6/macros-attributes/contract#analysis). - Uses your provided contract code to generate valid, optimized code for execution on-chain. @@ -162,26 +164,44 @@ the module declaration. mod helloink {} ``` -**Every ink! Smart Contract MUST have:** +Every **ink!** Smart Contract MUST have: - EXACTLY one `#[ink(storage)]` struct - AT LEAST one `#[ink(constructor)]` function - AT LEAST one `#[ink(message)]` function :::note -Learn more about the [ink::contract macro](https://use.ink/docs/v6/macros-attributes/contract) +Learn more about the [ink! contract macro](https://use.ink/docs/v6/macros-attributes/contract) ::: **Storage Declaration** +_Let's check out the storage declaration:_ + +Applies the `#[ink(storage)]` macro to the struct declaration. + +- Marks the `struct` type as the contract's storage definition. +- There must be ONLY one **ink!** storage definition per contract. +- Defines the layout of storage using a variety of built-in facilities. +- Advanced users can provide their own implementations of storage data structures. + +_In this case, we define a simple `bool` storage variable._ + ```rust #[ink(storage)] pub struct Helloink { - /// Stores a single `bool` value on the storage. value: bool, } ``` +:::note +Learn more about the [ink! storage macro](https://use.ink/docs/v6/macros-attributes/storage) + +Check out the Rust docs for a deeper dive +into the [ink_storage crate](https://docs.rs/ink_storage/latest/ink_storage/) + +::: + **Constructor and Message Declaration** ```rust @@ -203,28 +223,58 @@ Learn more about the [ink::contract macro](https://use.ink/docs/v6/macros-attrib } ``` +:::note +Learn more about the [ink! constructor macro](https://use.ink/docs/v6/macros-attributes/constructor) + +Learn more about the [ink! message macro](https://use.ink/docs/v6/macros-attributes/message) + +::: + ---- ### Executing Tests -**Run tests:** +**Build and run unit tests:** -```bash +Now, let's [build](https://learn.onpop.io/contracts/guides/build-your-contract) +and [test](https://learn.onpop.io/contracts/guides/run-your-unit-tests) our contract. +```bash +pop build --release +pop test ``` +:::note +Learn more about the [ink! testing strategies](https://use.ink/docs/v6/contract-testing/overview/) + +::: + ### Deploy to Testnet +Now, let's use the [Pop CLI to deploy our contract](https://learn.onpop.io/contracts/guides/deploy) to +a [local ink node](https://github.com/use-ink/ink-node) + **Deploy to testnet:** -```bash +- `-p` points to the contract directory +- `--constructor` method name (defaults to `new`) +- `--args` constructor arguments +- `--suri` secret key URI (default to `//Alice`) +- `--url` ink node url (default `ws://localhost:9944`) +```bash +pop up -p ./lib.rs \ + --constructor new \ + --args true \ + --suri //Alice ``` ---- ### Customizing the Code +Now that we understand each component of an **ink!** contract, let's jazz up the code to make it our own! + ```rust ``` @@ -237,4 +287,16 @@ Summarize the key takeaways from the tutorial. Suggest next steps, further readi ### Author -Write a short bio and link to your profile, blog, or project. +I'm Chris Anatalio, and I'm a Web3-native software engineer, technical educator, and developer advocate. I've +previously worked at ConsenSys, Stellar Development Foundation, and I produced a course +on [Web3 Infrastructure](https://www.pluralsight.com/courses/web3-infrastructure-development-tools) on +Pluralsight. I also run a small [web3 consultancy](https://hella.website/) + +I completed Polkadot Blockchain Academy Cohort 7 in Bali(2025) and have been a community member of the Polkadot +community since 2022. + +**Follow me on:** + +- [LinkedIn](https://www.linkedin.com/in/anataliocs/) +- [GitHub](https://github.com/anataliocs) +- [Twitter](https://x.com/CAnatalio) From 550defa2b7b49a91c9c918bc897b0e36286d512f Mon Sep 17 00:00:00 2001 From: Chris Anatalio Date: Tue, 2 Dec 2025 03:25:18 +0800 Subject: [PATCH 4/9] First draft of tutorial --- .../writing-your-first-smart-contract.md | 107 ++++++++++++------ 1 file changed, 73 insertions(+), 34 deletions(-) diff --git a/tutorials/writing-your-first-smart-contract.md b/tutorials/writing-your-first-smart-contract.md index 0d4930289c..4407015a44 100644 --- a/tutorials/writing-your-first-smart-contract.md +++ b/tutorials/writing-your-first-smart-contract.md @@ -3,9 +3,9 @@ title: Writing Your First Smart Contract sidebar_position: 2 --- ---- +![First Smart Contract Title Picture](/img/title/text/contract.svg) -### Overview +# Writing Your First Smart Contract We will walk through hand-on instructions to create a fully functional [ink!](https://use.ink/docs/v6) smart contract. @@ -32,7 +32,7 @@ Follow along with the companion GitHub repo [helloink](https://github.com/anatal ⭐️ _You will understand important concepts like storage, events and how to use them in your smart contract._ ::: -### Prerequisites +## Prerequisites _Here's what you'll need to get started:_ @@ -63,7 +63,7 @@ pop --version ---- -### Create a New Project with the Pop CLI +## Create a New Project with the Pop CLI :::note **Display available Pop CLI commands:** @@ -78,7 +78,7 @@ pop --help _First, let's create a new project using the `pop new` command:_ -**Create a new project:** +### Create a new project - Pass in `contract` to the command `pop new` - We name the contract`helloink` @@ -92,7 +92,7 @@ pop new contract helloink -t standard _Next, let's review the files that were generated:_ -**View files:** +### View Generated Files ```bash cd helloink @@ -121,11 +121,11 @@ _Import the project into your IDE and let's dig in!_ --- -### Reviewing the Generated Smart Contract +## Reviewing the Generated Smart Contract _Let's review each major component of the `lib.rs` file:_ -**Conditional Compilation Statement** +### Conditional Compilation Statement Configures [Conditional compilation](https://doc.rust-lang.org/reference/conditional-compilation.html) to ensure an optimal memory footprint and performance. @@ -140,12 +140,12 @@ ensure an optimal memory footprint and performance. ``` :::note -Check out +ℹ️ Check out the [FAQ](https://use.ink/docs/v6/faq/#what-does-the-cfg_attrnotfeature--std-no_std-no_main-at-the-beginning-of-each-contract-mean) for a more in-depth explanation. ::: -**Module Declaration** +### Module Declaration _Next, let's take a look at the module declaration:_ @@ -161,7 +161,9 @@ the module declaration. ```rust #[ink::contract] -mod helloink {} +mod helloink { + ///... +} ``` Every **ink!** Smart Contract MUST have: @@ -171,17 +173,17 @@ Every **ink!** Smart Contract MUST have: - AT LEAST one `#[ink(message)]` function :::note -Learn more about the [ink! contract macro](https://use.ink/docs/v6/macros-attributes/contract) +ℹ️ Learn more about the [ink! contract macro](https://use.ink/docs/v6/macros-attributes/contract) ::: -**Storage Declaration** +### Storage Declaration _Let's check out the storage declaration:_ Applies the `#[ink(storage)]` macro to the struct declaration. - Marks the `struct` type as the contract's storage definition. -- There must be ONLY one **ink!** storage definition per contract. +- There must be **ONLY** one **ink!** storage definition per contract. - Defines the layout of storage using a variety of built-in facilities. - Advanced users can provide their own implementations of storage data structures. @@ -195,14 +197,24 @@ _In this case, we define a simple `bool` storage variable._ ``` :::note -Learn more about the [ink! storage macro](https://use.ink/docs/v6/macros-attributes/storage) +ℹ️ Learn more about the [ink! storage macro](https://use.ink/docs/v6/macros-attributes/storage) -Check out the Rust docs for a deeper dive +ℹ️ Check out the Rust docs for a deeper dive into the [ink_storage crate](https://docs.rs/ink_storage/latest/ink_storage/) ::: -**Constructor and Message Declaration** +### Constructor Declaration + +_Let's take a look at the constructor declaration:_ + +Applies the `#[ink(constructor)]` macro to the `new()` function declaration. + +- Marks the function as the **ink!** constructor. +- Makes function available to the API for instantiating the contract. +- There must be **AT LEAST** one `#[ink(constructor)]` defined function. +- Dispatchable upon contract instantiation. +- Multiple constructors can be defined. ```rust impl Helloink { @@ -210,7 +222,33 @@ into the [ink_storage crate](https://docs.rs/ink_storage/latest/ink_storage/) pub fn new(init_value: bool) -> Self { Self { value: init_value } } + + ///... + } +``` + +### Message Declarations + +_Next, let's review the message declarations:_ + +Applies the `#[ink(message)]` macro to the `flip()` and `get()` function declarations. + +- Marks function as an **ink!** public message function +- Makes the function available for calling the contract. +- There must be **AT LEAST** one `#[ink(message)]` defined function. +- Dispatchable upon contract invocation +- The set of **ink!** messages defines its external API for users to invoke +- A message with a `&self` receiver may **ONLY** read state. +- A message with a `&mut self` receiver may modify state. + +:::note +⚠️ **ALL** public functions must use the #[ink(message)] attribute +::: +```rust + impl Helloink { + ///... + #[ink(message)] pub fn flip(&mut self) { self.value = !self.value; @@ -224,15 +262,15 @@ into the [ink_storage crate](https://docs.rs/ink_storage/latest/ink_storage/) ``` :::note -Learn more about the [ink! constructor macro](https://use.ink/docs/v6/macros-attributes/constructor) +ℹ️ Learn more about the [ink! constructor macro](https://use.ink/docs/v6/macros-attributes/constructor) -Learn more about the [ink! message macro](https://use.ink/docs/v6/macros-attributes/message) +ℹ️ Learn more about the [ink! message macro](https://use.ink/docs/v6/macros-attributes/message) ::: ---- -### Executing Tests +## Executing Tests **Build and run unit tests:** @@ -245,11 +283,11 @@ pop test ``` :::note -Learn more about the [ink! testing strategies](https://use.ink/docs/v6/contract-testing/overview/) +ℹ️ Learn more about the [ink! testing strategies](https://use.ink/docs/v6/contract-testing/overview/) ::: -### Deploy to Testnet +## Deploy to Testnet Now, let's use the [Pop CLI to deploy our contract](https://learn.onpop.io/contracts/guides/deploy) to a [local ink node](https://github.com/use-ink/ink-node) @@ -271,21 +309,22 @@ pop up -p ./lib.rs \ ---- -### Customizing the Code - -Now that we understand each component of an **ink!** contract, let's jazz up the code to make it our own! - -```rust - -``` - ----- +## Conclusion -### Conclusion +_Let's recap what we've done during this tutorial:_ -Summarize the key takeaways from the tutorial. Suggest next steps, further reading, or related tutorials. +- Generated an **ink!** smart contract using the Pop CLI (`pop new`) with the standard template +- Reviewed Rust conditional compilation for **ink!** contracts: `#![cfg_attr(not(feature = "std"), no_std, no_main)]` +- Walked through various **ink!** macros: + - `#[ink::contract]` Mark a module as an **ink!** contract, + - `#[ink(storage)]` Define the SINGLE storage struct, + - `#[ink(constructor)]` defines instantiation logic, + - `#[ink(message)]` defines public callable API (read-only with `&self` vs. state‑mutating with `&mut self`). +- Demonstrated contract storage by implementing a simple boolean field +- Built & tested the contract using Pop CLI commands (`pop build --release`, `pop test`) +- Deployed the contract to a local ink node using Pop CLI (`pop up`) -### Author +## Author I'm Chris Anatalio, and I'm a Web3-native software engineer, technical educator, and developer advocate. I've previously worked at ConsenSys, Stellar Development Foundation, and I produced a course From 07eed07c0639e4d0a21ee4f5849a4097e92a1159 Mon Sep 17 00:00:00 2001 From: Chris Anatalio Date: Wed, 3 Dec 2025 00:51:36 +0800 Subject: [PATCH 5/9] Update test, deploy and invoke sections --- .../writing-your-first-smart-contract.md | 167 +++++++++++++++--- 1 file changed, 146 insertions(+), 21 deletions(-) diff --git a/tutorials/writing-your-first-smart-contract.md b/tutorials/writing-your-first-smart-contract.md index 4407015a44..1b8bd52679 100644 --- a/tutorials/writing-your-first-smart-contract.md +++ b/tutorials/writing-your-first-smart-contract.md @@ -130,8 +130,8 @@ _Let's review each major component of the `lib.rs` file:_ Configures [Conditional compilation](https://doc.rust-lang.org/reference/conditional-compilation.html) to ensure an optimal memory footprint and performance. -- The `no_main` attribute is required to compile the contract for on-chain execution. -- The `no_std` ensures the standard library is not included in the contract. +- The `no_main` attribute is required to compile the contract for on-chain execution +- The `no_std` ensures the standard library is not included in the contract - The [Rust standard library](https://doc.rust-lang.org/std/) is OS-dependent and too heavyweight for on-chain use - More details on [no_std](https://docs.rust-embedded.org/book/intro/no-std.html) @@ -155,7 +155,7 @@ the module declaration. - Marks the module as an **ink!** contract and [checks for invalid arguments and structure](https://use.ink/docs/v6/macros-attributes/contract#analysis). - Uses your provided contract code to generate valid, optimized code for execution - on-chain. + on-chain - This allows you to simply define your contract's storage and other functionality without writing a bunch of complicated, boilerplate code! 😊 @@ -182,10 +182,10 @@ _Let's check out the storage declaration:_ Applies the `#[ink(storage)]` macro to the struct declaration. -- Marks the `struct` type as the contract's storage definition. -- There must be **ONLY** one **ink!** storage definition per contract. -- Defines the layout of storage using a variety of built-in facilities. -- Advanced users can provide their own implementations of storage data structures. +- Marks the `struct` type as the contract's storage definition +- There must be **ONLY** one **ink!** storage definition per contract +- Defines the layout of storage using a variety of built-in facilities +- Advanced users can provide their own implementations of storage data structures _In this case, we define a simple `bool` storage variable._ @@ -210,11 +210,11 @@ _Let's take a look at the constructor declaration:_ Applies the `#[ink(constructor)]` macro to the `new()` function declaration. -- Marks the function as the **ink!** constructor. -- Makes function available to the API for instantiating the contract. -- There must be **AT LEAST** one `#[ink(constructor)]` defined function. -- Dispatchable upon contract instantiation. -- Multiple constructors can be defined. +- Marks the function as the **ink!** constructor +- Makes function available to the API for instantiating the contract +- There must be **AT LEAST** one `#[ink(constructor)]` defined function +- Dispatchable upon contract instantiation +- Multiple constructors can be defined ```rust impl Helloink { @@ -270,18 +270,61 @@ Applies the `#[ink(message)]` macro to the `flip()` and `get()` function declara ---- -## Executing Tests - -**Build and run unit tests:** +## Build and Execute Tests Now, let's [build](https://learn.onpop.io/contracts/guides/build-your-contract) and [test](https://learn.onpop.io/contracts/guides/run-your-unit-tests) our contract. +**Build the contract:** + ```bash pop build --release +``` + +This will generate the following artifacts in `target/ink`: + +- `helloink.contract`: JSON with contract binary + metadata +- `helloink.polkavm`: Contract binary +- `helloink.json`: Contract metadata + +:::note +ℹ️ Learn more about [metadata](https://use.ink/docs/v6/basics/metadata/) + +ℹ️ Learn more about the [ink! metadata format](https://use.ink/docs/v6/basics/metadata/ink/) + +::: + +**Run the unit tests:** + +```bash pop test ``` +_Next, let's review the unit test:_ + +Applies the `#[cfg(test)]` macro to the `tests` module declaration. + +Applies the `#[ink::test]` macro to the `it_works()` function declaration. + +- Marks function as a unit test +- This macro is NOT strictly required to run unit tests that require ink!'s off-chain testing capabilities but + improves code readability. + +```rust + #[cfg(test)] + mod tests { + use super::*; + + #[ink::test] + fn it_works() { + let mut helloink = Helloink::new(false); + assert_eq!(helloink.get(), false); + helloink.flip(); + assert_eq!(helloink.get(), true); + } + } +``` + :::note ℹ️ Learn more about the [ink! testing strategies](https://use.ink/docs/v6/contract-testing/overview/) @@ -289,24 +332,106 @@ pop test ## Deploy to Testnet -Now, let's use the [Pop CLI to deploy our contract](https://learn.onpop.io/contracts/guides/deploy) to -a [local ink node](https://github.com/use-ink/ink-node) +Now, let's use [Pop to deploy our contract](https://learn.onpop.io/contracts/guides/deploy) to +a [local ink node](https://github.com/use-ink/ink-node). **Deploy to testnet:** -- `-p` points to the contract directory +- `--path` points to the contract directory - `--constructor` method name (defaults to `new`) - `--args` constructor arguments - `--suri` secret key URI (default to `//Alice`) - `--url` ink node url (default `ws://localhost:9944`) ```bash -pop up -p ./lib.rs \ +pop up --path . \ --constructor new \ --args true \ - --suri //Alice + --suri //Alice \ + --url ws://localhost:9944 +``` + +**The Pop CLI will prompt you to start a local node for the deployment:** + +- Select `Yes` to start the local ink node + +```terminaloutput +◆ No local ink! node detected. Would you like to start it node in the background for testing? +│ ● Yes / ○ No ``` +**The Pop CLI will prompt you to download the local node binary(During first run):** + +- Select `Yes` to download the local ink node binary + +```terminaloutput +▲ ⚠️ The ink-node binary is not found. +│ +◆ 📦 Would you like to source it automatically now? +│ ● Yes / ○ No +``` + +After the local ink node is started, you will be prompted to deploy the contract: + +- Select `Yes` to deploy your contract to the local ink node binary + +```terminaloutput +◆ Do you want to deploy the contract? (Selecting 'No' will keep this as a dry run) +│ ● Yes / ○ No +└ +``` + +_Congrats! You've successfully deployed your first **ink!** smart contract!_ + +```terminaloutput +⚙ Contract deployed and instantiated: +│ ● The contract address is "0x5801b439a678d9d3a68b8019da6a4abfa507de11" +``` + +### Invoke Deployed Contract + +Use the `pop call contract` command to invoke the deployed contract. + +```bash + pop call contract --path . \ + --contract 0x5801b439a678d9d3a68b8019da6a4abfa507de11 \ + --message flip \ + --url ws://localhost:9944/ \ + --suri //Alice \ + --execute +``` + +You should see something similar to the following output: + +```terminaloutput +⚙ Events +│ Event Balances ➜ Withdraw +│ who: 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY +│ amount: 1.204583894mUNIT +│ Event Balances ➜ BurnedDebt +│ amount: 1.204583894mUNIT +│ Event TransactionPayment ➜ TransactionFeePaid +│ who: 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY +│ actual_fee: 1.204583894mUNIT +│ tip: 0UNIT +│ Event System ➜ ExtrinsicSuccess +│ dispatch_info: DispatchEventInfo { weight: Weight { ref_time: 1204645303, proof_size: 37207 }, class: Normal, pays_fee: Yes } +``` + +Use the `pop call contract` command to get the contract storage current value. + +```bash +pop call contract --path . +--contract 0x5801b439a678d9d3a68b8019da6a4abfa507de11 +--message value +--url ws://localhost:9944/ +``` + +:::note +ℹ️ Learn more about the [Pop CLI call contract command](https://learn.onpop.io/contracts/guides/call-your-contract) + +::: + ---- ## Conclusion @@ -319,7 +444,7 @@ _Let's recap what we've done during this tutorial:_ - `#[ink::contract]` Mark a module as an **ink!** contract, - `#[ink(storage)]` Define the SINGLE storage struct, - `#[ink(constructor)]` defines instantiation logic, - - `#[ink(message)]` defines public callable API (read-only with `&self` vs. state‑mutating with `&mut self`). + - `#[ink(message)]` defines public callable API (read-only with `&self` vs. state‑mutating with `&mut self`) - Demonstrated contract storage by implementing a simple boolean field - Built & tested the contract using Pop CLI commands (`pop build --release`, `pop test`) - Deployed the contract to a local ink node using Pop CLI (`pop up`) From 27be434a2373bdc254b1080dbb78bc7b62002810 Mon Sep 17 00:00:00 2001 From: Chris Anatalio Date: Wed, 3 Dec 2025 15:51:58 +0800 Subject: [PATCH 6/9] Proofread and cleanup --- .../writing-your-first-smart-contract.md | 93 +++++++++++++------ 1 file changed, 64 insertions(+), 29 deletions(-) diff --git a/tutorials/writing-your-first-smart-contract.md b/tutorials/writing-your-first-smart-contract.md index 1b8bd52679..8c2ef2809a 100644 --- a/tutorials/writing-your-first-smart-contract.md +++ b/tutorials/writing-your-first-smart-contract.md @@ -12,6 +12,10 @@ fully functional [ink!](https://use.ink/docs/v6) smart contract. Follow along with the companion GitHub repo [helloink](https://github.com/anataliocs/helloink). +This is a template repo. Click +the [Use this Template](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template) +button to create your own repo to follow along with this tutorial. + **We will break down and explain key concepts including:** - Using the Pop CLI @@ -23,23 +27,28 @@ Follow along with the companion GitHub repo [helloink](https://github.com/anatal :::note **Learning Objectives:** -⭐️ _By the end of this tutorial, you will be able to write, compile, build, test and deploy **ink!** contracts._ +⭐️ _By the end of this tutorial, you will be able to write, build, test and deploy **ink!** contracts_ -⭐️ _You will be familiar with all the key components of **ink!** smart contract._ +⭐️ _You will be familiar with all the key components of an **ink!** smart contract_ -⭐️ _You will understand how to use the Pop CLI._ +⭐️ _You will understand how to use the Pop CLI_ -⭐️ _You will understand important concepts like storage, events and how to use them in your smart contract._ +⭐️ _You will understand important concepts like storage, events and how to use them in your smart contract_ ::: ## Prerequisites _Here's what you'll need to get started:_ -- Install Brew: https://brew.sh/ +Follow the steps in the [ink! Getting Started Guide](https://use.ink/docs/v6/getting-started/setup) to: + +- Install [Brew](https://brew.sh/) - Install [Rust](https://rust-lang.org/tools/install/), [Cargo](https://doc.rust-lang.org/cargo/) - and [Pop CLI](https://github.com/r0gue-io/pop-cli): https://use.ink/docs/v6/getting-started/setup -- Read up on the [Pop CLI](https://learn.onpop.io/) + and [Pop CLI](https://github.com/r0gue-io/pop-cli) + +:::note +Read up on the [Pop CLI](https://learn.onpop.io/) +::: _After that, let's verify everything is installed correctly:_ @@ -78,7 +87,7 @@ pop --help _First, let's create a new project using the `pop new` command:_ -### Create a new project +### Create a New Project - Pass in `contract` to the command `pop new` - We name the contract`helloink` @@ -135,6 +144,8 @@ ensure an optimal memory footprint and performance. - The [Rust standard library](https://doc.rust-lang.org/std/) is OS-dependent and too heavyweight for on-chain use - More details on [no_std](https://docs.rust-embedded.org/book/intro/no-std.html) +**lib.rs** (excerpt) + ```rust #![cfg_attr(not(feature = "std"), no_std, no_main)] ``` @@ -159,6 +170,8 @@ the module declaration. - This allows you to simply define your contract's storage and other functionality without writing a bunch of complicated, boilerplate code! 😊 +**lib.rs** (excerpt) + ```rust #[ink::contract] mod helloink { @@ -189,6 +202,8 @@ Applies the `#[ink(storage)]` macro to the struct declaration. _In this case, we define a simple `bool` storage variable._ +**lib.rs** (excerpt) + ```rust #[ink(storage)] pub struct Helloink { @@ -216,6 +231,8 @@ Applies the `#[ink(constructor)]` macro to the `new()` function declaration. - Dispatchable upon contract instantiation - Multiple constructors can be defined +**lib.rs** (excerpt) + ```rust impl Helloink { #[ink(constructor)] @@ -233,17 +250,19 @@ _Next, let's review the message declarations:_ Applies the `#[ink(message)]` macro to the `flip()` and `get()` function declarations. -- Marks function as an **ink!** public message function -- Makes the function available for calling the contract. -- There must be **AT LEAST** one `#[ink(message)]` defined function. +- Marks functions as **ink!** public message functions +- There must be **AT LEAST** one `#[ink(message)]` defined function in a contract - Dispatchable upon contract invocation -- The set of **ink!** messages defines its external API for users to invoke -- A message with a `&self` receiver may **ONLY** read state. -- A message with a `&mut self` receiver may modify state. +- The set of **ink!** messages defines its external API available for invocation :::note ⚠️ **ALL** public functions must use the #[ink(message)] attribute -::: + +- A message with a `&self` receiver may **ONLY** read state +- A message with a `&mut self` receiver may modify state + ::: + +**lib.rs** (excerpt) ```rust impl Helloink { @@ -272,10 +291,10 @@ Applies the `#[ink(message)]` macro to the `flip()` and `get()` function declara ## Build and Execute Tests -Now, let's [build](https://learn.onpop.io/contracts/guides/build-your-contract) -and [test](https://learn.onpop.io/contracts/guides/run-your-unit-tests) our contract. +_Now, let's [build](https://learn.onpop.io/contracts/guides/build-your-contract) +and [test](https://learn.onpop.io/contracts/guides/run-your-unit-tests) our contract._ -**Build the contract:** +### Build the Contract ```bash pop build --release @@ -294,21 +313,25 @@ This will generate the following artifacts in `target/ink`: ::: -**Run the unit tests:** +### Run the Unit Tests ```bash pop test ``` -_Next, let's review the unit test:_ +### Review Unit Test Code + +_Next, let's review the unit test code:_ Applies the `#[cfg(test)]` macro to the `tests` module declaration. Applies the `#[ink::test]` macro to the `it_works()` function declaration. -- Marks function as a unit test -- This macro is NOT strictly required to run unit tests that require ink!'s off-chain testing capabilities but - improves code readability. +- Marks function as an **ink!** unit test +- This macro is NOT strictly required to run unit tests that require **ink!** off-chain testing capabilities but + improves code readability + +**lib.rs** (excerpt) ```rust #[cfg(test)] @@ -330,12 +353,12 @@ Applies the `#[ink::test]` macro to the `it_works()` function declaration. ::: -## Deploy to Testnet +## Deploy to Local Ink Node Now, let's use [Pop to deploy our contract](https://learn.onpop.io/contracts/guides/deploy) to a [local ink node](https://github.com/use-ink/ink-node). -**Deploy to testnet:** +### Deploy to Local Node using Pop CLI - `--path` points to the contract directory - `--constructor` method name (defaults to `new`) @@ -388,9 +411,17 @@ _Congrats! You've successfully deployed your first **ink!** smart contract!_ │ ● The contract address is "0x5801b439a678d9d3a68b8019da6a4abfa507de11" ``` -### Invoke Deployed Contract +:::note +ℹ️ Learn more about the [ink! local node](https://github.com/use-ink/ink-node) + +::: + +## Invoke Deployed Contract -Use the `pop call contract` command to invoke the deployed contract. +_We will use the `pop call contract` command to invoke the deployed contract:_ + +- Replace the hash passed into the `--contract` argument with the deployed contract address from the previous step +- This command will invoke the `flip()` function mutating the state of the boolean storage variable ```bash pop call contract --path . \ @@ -418,6 +449,8 @@ You should see something similar to the following output: │ dispatch_info: DispatchEventInfo { weight: Weight { ref_time: 1204645303, proof_size: 37207 }, class: Normal, pays_fee: Yes } ``` +### Read the Current Contract Storage Value + Use the `pop call contract` command to get the contract storage current value. ```bash @@ -436,7 +469,7 @@ pop call contract --path . ## Conclusion -_Let's recap what we've done during this tutorial:_ +_Let's recap what we've accomplished during this tutorial:_ - Generated an **ink!** smart contract using the Pop CLI (`pop new`) with the standard template - Reviewed Rust conditional compilation for **ink!** contracts: `#![cfg_attr(not(feature = "std"), no_std, no_main)]` @@ -445,9 +478,11 @@ _Let's recap what we've done during this tutorial:_ - `#[ink(storage)]` Define the SINGLE storage struct, - `#[ink(constructor)]` defines instantiation logic, - `#[ink(message)]` defines public callable API (read-only with `&self` vs. state‑mutating with `&mut self`) -- Demonstrated contract storage by implementing a simple boolean field +- Demonstrated contract storage by implementing a simple boolean field and message functions to read and mutate that + storage variable - Built & tested the contract using Pop CLI commands (`pop build --release`, `pop test`) - Deployed the contract to a local ink node using Pop CLI (`pop up`) +- Invoked the contract using Pop CLI (`pop call contract`) ## Author From abb37d2dafd29e246a7dc07a566509c61c0a792c Mon Sep 17 00:00:00 2001 From: Chris Anatalio Date: Wed, 3 Dec 2025 16:04:21 +0800 Subject: [PATCH 7/9] Fix link syntax --- tutorials/writing-your-first-smart-contract.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tutorials/writing-your-first-smart-contract.md b/tutorials/writing-your-first-smart-contract.md index 8c2ef2809a..34083b7e52 100644 --- a/tutorials/writing-your-first-smart-contract.md +++ b/tutorials/writing-your-first-smart-contract.md @@ -160,7 +160,7 @@ for a more in-depth explanation. _Next, let's take a look at the module declaration:_ -Applies the `#[ink::contract]` [proc macro attribute]((https://doc.rust-lang.org/reference/procedural-macros.html)) to +Applies the `#[ink::contract]` [proc macro attribute](https://doc.rust-lang.org/reference/procedural-macros.html) to the module declaration. - Marks the module as an **ink!** contract From c314c9d65bf1d4f2a34cde653dc30cd75ded8607 Mon Sep 17 00:00:00 2001 From: Chris Anatalio Date: Wed, 3 Dec 2025 20:54:27 +0800 Subject: [PATCH 8/9] Fix pop call contract command --- tutorials/writing-your-first-smart-contract.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tutorials/writing-your-first-smart-contract.md b/tutorials/writing-your-first-smart-contract.md index 34083b7e52..10241c2f51 100644 --- a/tutorials/writing-your-first-smart-contract.md +++ b/tutorials/writing-your-first-smart-contract.md @@ -451,12 +451,15 @@ You should see something similar to the following output: ### Read the Current Contract Storage Value -Use the `pop call contract` command to get the contract storage current value. +_Use the `pop call contract` command to get the contract storage current value._ + +- Replace the hash passed into the `--contract` argument with the deployed contract address from the previous step +- This retrieves and displays the current state of the boolean storage variable ```bash -pop call contract --path . ---contract 0x5801b439a678d9d3a68b8019da6a4abfa507de11 ---message value +pop call contract --path . \ +--contract 0x5801b439a678d9d3a68b8019da6a4abfa507de11 \ +--message value \ --url ws://localhost:9944/ ``` From c5bac7437926bcb14a82dea4f4a328c2de2d3c1f Mon Sep 17 00:00:00 2001 From: Chris Anatalio Date: Thu, 4 Dec 2025 14:31:06 +0800 Subject: [PATCH 9/9] Add more detailed config steps, proofreading and readability improvements --- .../writing-your-first-smart-contract.md | 52 ++++++++++++++----- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/tutorials/writing-your-first-smart-contract.md b/tutorials/writing-your-first-smart-contract.md index 10241c2f51..7e0f8c6d2a 100644 --- a/tutorials/writing-your-first-smart-contract.md +++ b/tutorials/writing-your-first-smart-contract.md @@ -12,17 +12,13 @@ fully functional [ink!](https://use.ink/docs/v6) smart contract. Follow along with the companion GitHub repo [helloink](https://github.com/anataliocs/helloink). -This is a template repo. Click -the [Use this Template](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template) -button to create your own repo to follow along with this tutorial. - **We will break down and explain key concepts including:** - Using the Pop CLI - Storage: Reading, Writing & Mutating Storage - Constructors - Messages -- Ink contract macros +- Ink Contract Macros :::note **Learning Objectives:** @@ -33,12 +29,30 @@ button to create your own repo to follow along with this tutorial. ⭐️ _You will understand how to use the Pop CLI_ -⭐️ _You will understand important concepts like storage, events and how to use them in your smart contract_ +⭐️ _You will understand important concepts like storage and messages and how to use them in your smart contract_ ::: ## Prerequisites -_Here's what you'll need to get started:_ +There are two ways to follow along with this tutorial! + +### GitHub Codespace + +_You can create your own repo to follow along with this tutorial in a Github Codespace!_ + +The companion GitHub repo [helloink](https://github.com/anataliocs/helloink). + +This is a template repo. Click +the [Use this Template](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template) +button to create your own repo to follow along with this tutorial. + +The included `.devcontainer` config creates a GitHub codespace pre-installed with Rust, Cargo, and the Pop CLI so you +can hit the ground running. Learn more +about [Devcontainers](https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers). + +### Local Config + +_Or if you want to follow along on your local machine, here's what you'll need to get started!_ Follow the steps in the [ink! Getting Started Guide](https://use.ink/docs/v6/getting-started/setup) to: @@ -50,7 +64,9 @@ Follow the steps in the [ink! Getting Started Guide](https://use.ink/docs/v6/get Read up on the [Pop CLI](https://learn.onpop.io/) ::: -_After that, let's verify everything is installed correctly:_ +### Verify Installation + +_In both cases, let's verify everything is installed correctly:_ **Verify Rust version:** @@ -58,18 +74,24 @@ _After that, let's verify everything is installed correctly:_ rustc --version ``` +rustc version 1.91.1 or higher is recommended. + **Verify Cargo version:** ```bash cargo --version ``` +cargo version 1.91.1 or higher is recommended. + **Verify Pop CLI version:** ```bash pop --version ``` +pop cli version 0.12.1 or higher is recommended. + ---- ## Create a New Project with the Pop CLI @@ -394,7 +416,7 @@ pop up --path . \ │ ● Yes / ○ No ``` -After the local ink node is started, you will be prompted to deploy the contract: +**After the local ink node is started, you will be prompted to deploy the contract:** - Select `Yes` to deploy your contract to the local ink node binary @@ -404,7 +426,9 @@ After the local ink node is started, you will be prompted to deploy the contract └ ``` -_Congrats! You've successfully deployed your first **ink!** smart contract!_ +### Successful Deployment + +_Congrats! You've successfully deployed your first **ink!** smart contract!_ 🎉 ```terminaloutput ⚙ Contract deployed and instantiated: @@ -477,11 +501,11 @@ _Let's recap what we've accomplished during this tutorial:_ - Generated an **ink!** smart contract using the Pop CLI (`pop new`) with the standard template - Reviewed Rust conditional compilation for **ink!** contracts: `#![cfg_attr(not(feature = "std"), no_std, no_main)]` - Walked through various **ink!** macros: - - `#[ink::contract]` Mark a module as an **ink!** contract, - - `#[ink(storage)]` Define the SINGLE storage struct, - - `#[ink(constructor)]` defines instantiation logic, + - `#[ink::contract]` Mark a module as an **ink!** contract + - `#[ink(storage)]` Define the SINGLE storage struct + - `#[ink(constructor)]` defines instantiation logic - `#[ink(message)]` defines public callable API (read-only with `&self` vs. state‑mutating with `&mut self`) -- Demonstrated contract storage by implementing a simple boolean field and message functions to read and mutate that +- Demonstrated contract storage by implementing a simple boolean field and message function to read and mutate that storage variable - Built & tested the contract using Pop CLI commands (`pop build --release`, `pop test`) - Deployed the contract to a local ink node using Pop CLI (`pop up`)