+ A basic web3 example with Starknet +
+diff --git a/chapters/book/modules/chapter_2/images/basic_dapp_abi.png b/chapters/book/modules/chapter_2/images/basic_dapp_abi.png new file mode 100644 index 000000000..17019c7fe Binary files /dev/null and b/chapters/book/modules/chapter_2/images/basic_dapp_abi.png differ diff --git a/chapters/book/modules/chapter_2/images/basic_dapp_abi_new.png b/chapters/book/modules/chapter_2/images/basic_dapp_abi_new.png new file mode 100644 index 000000000..eb83e6c78 Binary files /dev/null and b/chapters/book/modules/chapter_2/images/basic_dapp_abi_new.png differ diff --git a/chapters/book/modules/chapter_2/images/basic_dapp_erc20.png b/chapters/book/modules/chapter_2/images/basic_dapp_erc20.png new file mode 100644 index 000000000..af0d055b2 Binary files /dev/null and b/chapters/book/modules/chapter_2/images/basic_dapp_erc20.png differ diff --git a/chapters/book/modules/chapter_2/images/basic_dapp_localhost.png b/chapters/book/modules/chapter_2/images/basic_dapp_localhost.png new file mode 100644 index 000000000..98eadc5ac Binary files /dev/null and b/chapters/book/modules/chapter_2/images/basic_dapp_localhost.png differ diff --git a/chapters/book/modules/chapter_2/images/basic_dapp_pub1.png b/chapters/book/modules/chapter_2/images/basic_dapp_pub1.png new file mode 100644 index 000000000..5ff28be69 Binary files /dev/null and b/chapters/book/modules/chapter_2/images/basic_dapp_pub1.png differ diff --git a/chapters/book/modules/chapter_2/images/basic_dapp_pub2.png b/chapters/book/modules/chapter_2/images/basic_dapp_pub2.png new file mode 100644 index 000000000..1f9d45fd2 Binary files /dev/null and b/chapters/book/modules/chapter_2/images/basic_dapp_pub2.png differ diff --git a/chapters/book/modules/chapter_2/images/basic_dapp_pub3.png b/chapters/book/modules/chapter_2/images/basic_dapp_pub3.png new file mode 100644 index 000000000..bcf22e957 Binary files /dev/null and b/chapters/book/modules/chapter_2/images/basic_dapp_pub3.png differ diff --git a/chapters/book/modules/chapter_2/images/basic_dapp_pub4.png b/chapters/book/modules/chapter_2/images/basic_dapp_pub4.png new file mode 100644 index 000000000..a69c76dd5 Binary files /dev/null and b/chapters/book/modules/chapter_2/images/basic_dapp_pub4.png differ diff --git a/chapters/book/modules/chapter_2/images/basic_dapp_react_files.png b/chapters/book/modules/chapter_2/images/basic_dapp_react_files.png new file mode 100644 index 000000000..ada8a8beb Binary files /dev/null and b/chapters/book/modules/chapter_2/images/basic_dapp_react_files.png differ diff --git a/chapters/book/modules/chapter_2/images/basic_dapp_screenshot.png b/chapters/book/modules/chapter_2/images/basic_dapp_screenshot.png new file mode 100644 index 000000000..eac10401a Binary files /dev/null and b/chapters/book/modules/chapter_2/images/basic_dapp_screenshot.png differ diff --git a/chapters/book/modules/chapter_2/images/basic_dapp_vercel_login.png b/chapters/book/modules/chapter_2/images/basic_dapp_vercel_login.png new file mode 100644 index 000000000..d14cd6814 Binary files /dev/null and b/chapters/book/modules/chapter_2/images/basic_dapp_vercel_login.png differ diff --git a/chapters/book/modules/chapter_2/images/basic_dapp_vercel_verify.png b/chapters/book/modules/chapter_2/images/basic_dapp_vercel_verify.png new file mode 100644 index 000000000..6eea1262e Binary files /dev/null and b/chapters/book/modules/chapter_2/images/basic_dapp_vercel_verify.png differ diff --git a/chapters/book/modules/chapter_2/nav.adoc b/chapters/book/modules/chapter_2/nav.adoc new file mode 100644 index 000000000..7d59f78bd --- /dev/null +++ b/chapters/book/modules/chapter_2/nav.adoc @@ -0,0 +1,14 @@ +* xref:index.adoc[2. Starknet Tooling] + ** xref:scarb.adoc[Scarb: Package Manager] + ** xref:katana.adoc[Local Node for Development] + ** xref:hardhat.adoc[Starknet-Hardhat] + ** xref:protostar.adoc[Protostar] + ** xref:starknetjs.adoc[Starknet.js] + ** xref:starknetrs.adoc[Starknet-rs 🚧] + ** xref:starknetpy.adoc[Starknet_py 🚧] + ** xref:testing.adoc[Testing 🚧] + ** xref:starknet-react.adoc[Starknet React] + ** xref:starknet-react-basic.adoc[Starknet React Basic Example] + ** xref:bridges.adoc[Bridges 🚧] + ** xref:oracles.adoc[Oracles] + ** xref:indexers-explorers.adoc[Indexers and Explorers] diff --git a/chapters/book/modules/chapter_2/pages/starknet-react-basic.adoc b/chapters/book/modules/chapter_2/pages/starknet-react-basic.adoc new file mode 100644 index 000000000..c5aa44ce2 --- /dev/null +++ b/chapters/book/modules/chapter_2/pages/starknet-react-basic.adoc @@ -0,0 +1,613 @@ +[id="starknet-react-basic"] + += Starknet React: A basic full example. + + +This tutorial will teach you how to build an ERC20 smart contract in Cairo and integrate it into a React web application using StarkNet React. You will learn how to implement the ERC20 interface, deploy your contract to the StarkNet network, and interact with your contract from your React application. By following this tutorial, you will be able to create your own ERC20 token and deploy it to StarkNet. + +This tutorial is suitable for beginners with a basic knowledge of Cairo programming language and ReactJS. You will also need to have Node.js and NPM installed on your machine. + +We'll create an ERC20 token named MKT and build a web3 interface to interact with it, providing functionalities like checking the balance and transferring tokens. + +image::basic_dapp_screenshot.png[screenshot] + +Along this tutorial, we will be using the following tools and libraries: + +- Scarb 0.7.0 with Cairo 2.2.0 +- Starkli 0.1.9 +- Oppenzeppelin libraries v0.7.0 +- Starknet React v1.0.4 +- NodeJS v19.6.1 +- Next.js 13.1.6 +- Visual Studio Code +- Vercel + +== Create a new StarkNet project + +First, let's create a new StarkNet project named "erc20" using Scarb: + +[source,bash] +---- +~$ mkdir erc20 +~$ cd erc20 +~/erc20$ scarb init --name erc20 +Created package. +~/erc20$ +---- + +Edit your Scarb.toml and add the necessary OpenZeppelin libraries. Your Scarb.toml file should resemble the following: + +[source,rust] +---- +[package] +name = "erc20" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html + +[dependencies] +starknet = ">=2.2.0" +openzeppelin = { git = "https://github.com/OpenZeppelin-contracts.git", tag = "v0.7.0" } + +[[target.starknet-contract]] +---- + +== Implement the ERC20 token + +Now, create a new file named src/erc20.cairo where we will define our ERC20 token, MKT, and its functions for checking the balance and transferring tokens: + +[source,rust] +---- +#[starknet::contract] +mod erc20 { + use starknet::ContractAddress; + use openzeppelin::token::erc20::ERC20; + + #[storage] + struct Storage {} + + #[constructor] + fn constructor( + ref self: ContractState, + initial_supply: u256, + recipient: ContractAddress + ) { + let name = 'MyToken'; + let symbol = 'MTK'; + + let mut unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::InternalImpl::initializer(ref unsafe_state, name, symbol); + ERC20::InternalImpl::_mint(ref unsafe_state, recipient, initial_supply); + } + + #[external(v0)] + #[generate_trait] + impl Ierc20Impl of Ierc20 { + fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { + let unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20Impl::balance_of(@unsafe_state, account) + } + + fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool { + let mut unsafe_state = ERC20::unsafe_new_contract_state(); + ERC20::ERC20Impl::transfer(ref unsafe_state, recipient, amount) + } + } +} +---- + +image::basic_dapp_erc20.png[screenshot] + +Once you've written your contract, compile it with Scarb: + +[source,yaml] +---- +~/erc20$ scarb build + Updating git repository https://github.com/openzeppelin-contracts + Compiling erc20 v0.1.0 (/home/kali/erc20/Scarb.toml) + Finished release target(s) in 6 seconds +~/erc20$ +---- + +Afterward, declare your smart contract on Starknet testnet: + +[source,yaml] +---- +~/erc20$ starkli declare target/dev/erc20_erc20.sierra.json --account ../../demo-account.json --keystore ../../demo-key.json --compiler-version 2.1.0 --network goerli-1 --watch +WARNING: you´re using the sequencer gateway instead of providing a JSON-RPC endpoint. This is strongly discouraged. See https://book.starkli.rs/providers for more details. +Enter keystore password: +Declaring Cairo 1 class: 0x04940154eae35788e899ceb0ef2794eaa5ea6818af5c1c726d6d278fd4979713 +Compiling Sierra class to CASM with compiler version 2.1.0... +CASM class hash: 0x065d12bc099e19b12d1ded4c27a21d6b5d4f9e5a95f5e2f093452d2d386e4936 +Contract declaration transaction: 0x02f111205d373fad6acfe0d14c34046283d7fa5cb30a3edac97e8bce7699cb57 +Waiting for transaction 0x02f111205d373fad6acfe0d14c34046283d7fa5cb30a3edac97e8bce7699cb57 to confirm... +Transaction not confirmed yet... +Transaction 0x02f111205d373fad6acfe0d14c34046283d7fa5cb30a3edac97e8bce7699cb57 confirmed +Class hash declared: +0x04940154eae35788e899ceb0ef2794eaa5ea6818af5c1c726d6d278fd4979713 +~/erc20$ +---- + +If you haven't made any changes to our example contract, you'll receive a note confirming that your contract has been already declared in the past in Starknet: + +[source,yaml] +---- +~/erc20$ starkli declare target/dev/erc20_erc20.sierra.json --account ../../demo-account.json --keystore ../../demo-key.json --compiler-version 2.1.0 --network goerli-1 --watch +WARNING: you´re using the sequencer gateway instead of providing a JSON-RPC endpoint. This is strongly discouraged. See https://book.starkli.rs/providers for more details. +Enter keystore password: +Not declaring class as it's already declared. Class hash: +0x04940154eae35788e899ceb0ef2794eaa5ea6818af5c1c726d6d278fd4979713 +~/erc20$ +---- + +== Deploy your ERC20 contract + +Now, let's deploy the MKT Token using Starkli. You'll need to provide the following arguments: + +- `Initial mint`: We will mint 1,000,000 tokens, but since our MKT token has 18 decimals (OpenZeppelin default), we need to pass 1,000,000 * 10^18 = 0xd3c21bcecceda1000000. Also, as our contract expects a u256 mint value, we need to pass two values for low and high values: 0xd3c21bcecceda1000000 0. +- `Receiver address`: You can use your own address. In this example, we will use: 0x0334863e3e851de87fb4b6b6113aa2a6b40ea20f22dbec55536e4eac912206fc + +[source,yaml] +---- +~/erc20$ starkli deploy 0x04940154eae35788e899ceb0ef2794eaa5ea6818af5c1c726d6d278fd4979713 --account ../../demo-account.json --keystore ../../demo-key.json --network goerli-1 --watch 0xd3c21bcecceda1000000 0 0x0334863e3e851de87fb4b6b6113aa2a6b40ea20f22dbec55536e4eac912206fc +WARNING: you re using the sequencer gateway instead of providing a JSON-RPC endpoint. This is strongly discouraged. See https://book.starkli.rs/providers for more details. +Enter keystore password: +Deploying class 0x04940154eae35788e899ceb0ef2794eaa5ea6818af5c1c726d6d278fd4979713 with salt 0x03628d1f523b9980306bf8e7226a3c24b0f618689f7a6b484439488b650ee418... +The contract will be deployed at address 0x001892d81e09cb2c2005f0112891dacb92a6f8ce571edd03ed1f3e549abcf37f +Contract deployment transaction: 0x04945fb3765ce729e0c6ef90c4b6fbba908afad9b22650d152bb7c84a65f30dc +Waiting for transaction 0x04945fb3765ce729e0c6ef90c4b6fbba908afad9b22650d152bb7c84a65f30dc to confirm... +Transaction not confirmed yet... +Transaction 0x04945fb3765ce729e0c6ef90c4b6fbba908afad9b22650d152bb7c84a65f30dc confirmed +Contract deployed: +0x001892d81e09cb2c2005f0112891dacb92a6f8ce571edd03ed1f3e549abcf37f +~/erc20$ +---- + +[NOTE] +==== +You will receive a different deployed address; keep this address to replace it in the next section's TypeScript files with your contract address. +==== + +Congratulations! You've successfully deployed your Cairo ERC20 smart contract on Starknet.. + +== Install the StarkNet React library + +With your contract deployed, it's time to start building your web application. First, install the Starknet React library: + +[source,bash] +---- +~$ npm add @starknet-react/core + +added 36 packages, and audited 621 packages in 13s + +15 packages are looking for funding + run `npm fund` for details + +56 vulnerabilities (2 low, 20 moderate, 24 high, 10 critical) + +To address issues that do not require attention, run: + npm audit fix + +To address all issues (including breaking changes), run: + npm audit fix --force + +Run `npm audit` for details. +~$ +---- + +You can check the installed version by running: + +[source,bash] +---- +~$ npm list @starknet-react/core +kali@ /home/kali +└── @starknet-react/core@1.0.4 + +~$ +---- + +== Create a new React project + +The Starknet React library includes a create-starknet script that automatically sets up a Starknet app using TypeScript: + +[source,bash] +---- +~$ npx create-starknet erc20_web --use-npm +✔ What framework would you like to use? › Next.js +Installing dependencies... +Success! Created erc20_web at /home/kali/erc20_web + +We suggest that you begin by typing: + + cd erc20_web + npm run dev +~$ +---- + +Edit erc20_web/index.tsx and replace its contents with the provided code: + +[source,typescript] +---- +import Head from 'next/head' +import { useBlock } from '@starknet-react/core' +import WalletBar from '../components/WalletBar' +import { BlockTag } from 'starknet'; + +export default function Home() { + const { data, isLoading, isError } = useBlock({ + refetchInterval: 3000, + blockIdentifier: BlockTag.latest, + }) + return ( + <> +
++ A basic web3 example with Starknet +
+Balance.
+{data?data.toString(): 0}
+ +Transfer.
+Recipient: + +
+Amount (default 1 MKT with 18 decimals): + +
++ +
++ {connectors.map((connector) => { + return ( + + ) + })} +
+