diff --git a/.all-contributorsrc b/.all-contributorsrc index e36d3e70a..75e93f703 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -8,4 +8,4 @@ "commit": true, "commitConvention": "gitmoji", "contributorsPerLine": 7 -} \ No newline at end of file +} diff --git a/README.md b/README.md index 304e094a3..27672c08a 100644 --- a/README.md +++ b/README.md @@ -83,4 +83,4 @@ For starting translations in a new language: - \ No newline at end of file + diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 4639b4542..e2c450faf 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -20,8 +20,10 @@ - [Examples](ch02-07-01-examples.md) - [Beginner - Counter UI](ch02-07-01-00-counter-ui.md) - [Beginner - ERC-20 UI](ch02-07-01-01-erc20-ui.md) - - [Intermediate - Million Dollar Homepage](ch02-07-01-02-million-dollar-homepage.md) - [Starknet-React: React Integration](ch02-08-starknet-react.md) + - [Examples](ch02-08-01-examples.md) + - [Beginner - ERC-20 UI](ch02-08-01-01-erc20-ui.md) + - [Intermediate - Million Dollar Homepage](ch02-07-01-02-million-dollar-homepage.md) - [Starknet-py: Python SDK 🚧](ch02-09-starknet-py.md) - [Starknet-rs: Rust SDK 🚧](ch02-10-starknet-rs.md) - [Foundry Cast: Interacting with Starknet](ch02-11-foundry-cast.md) diff --git a/src/ch02-07-01-01-erc20-ui.md b/src/ch02-07-01-01-erc20-ui.md index 50337f425..752ce63a7 100644 --- a/src/ch02-07-01-01-erc20-ui.md +++ b/src/ch02-07-01-01-erc20-ui.md @@ -1,26 +1,27 @@ # ERC-20 UI -This guide offers steps to build an ERC20 smart contract using Cairo and to incorporate it within a React web application with Starknet React. Readers will: +This guide offers steps to build an ERC20 smart contract using Cairo and to incorporate it within a React web application with StarknetJS. Readers will: - Understand how to implement the ERC20 interface - Learn how to deploy contracts on the Starknet network - Discover ways to engage with contracts within a React application - Design their own ERC20 token and initiate it on Starknet -A prerequisite for this guide is a foundational understanding of both the Cairo programming language and ReactJS. Additionally, ensure Node.js and NPM are installed on the system. +A prerequisite for this guide is a foundational understanding of both the Cairo programming language and StarknetJS. Additionally, ensure Node.js and NPM are installed on the system. The example will walk through creating an ERC20 token named MKT and crafting a web3 interface for functionalities such as balance verification and token transfer. -Basic Dapp ERC20 +Basic Dapp ERC20 Throughout this guide, the following tools and libraries will be utilized: - Scarb 0.7.0 with Cairo 2.2.0 - Starkli 0.1.9 - Oppenzeppelin libraries v0.7.0 -- Starknet React v1.0.4 +- StarknetJS v5.19.5 +- get-starknet v3.0.1 - NodeJS v19.6.1 -- Next.js 13.1.6 +- Next.js 13.5.5 - Visual Studio Code - Vercel @@ -93,7 +94,15 @@ mod erc20 { } ``` -Basic Dapp ERC20 +Basic Dapp ERC20 + +Now edit `src/lib.cairo` and replace the content with: + +```rust +mod erc20; +``` + +Basic Dapp ERC20 Upon completing your contract, proceed to compile it using Scarb: @@ -101,7 +110,7 @@ Upon completing your contract, proceed to compile it using Scarb: scarb build ``` -Subsequent to the compilation, declare the smart contract on the Starknet testnet: +Subsequent to the compilation, declare the smart contract on the Starknet testnet (using your own account and keystore): ```bash 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 @@ -128,7 +137,7 @@ Not declaring class as it's already declared. Class hash: 0x04940154eae35788e899 Proceed to deploy the MKT Token using Starkli. Provide these arguments for successful deployment: - `Initial mint`: Mint 1,000,000 tokens. Given that the MKT token comprises 18 decimals (a standard of OpenZeppelin), the input required is 1,000,000 \* 10^18 or 0xd3c21bcecceda1000000. Due to the contract's expectation of a u256 mint value, provide both low and high values: 0xd3c21bcecceda1000000 and 0 respectively. -- `Receiver address`: Use a preferred address. In this example: 0x0334863e3e851de87fb4b6b6113aa2a6b40ea20f22dbec55536e4eac912206fc +- `Receiver address`: Use a preferred address who wiil be the initial recipient of 1,000,000 MKT. In this example: 0x0334863e3e851de87fb4b6b6113aa2a6b40ea20f22dbec55536e4eac912206fc ```bash starkli deploy 0x04940154eae35788e899ceb0ef2794eaa5ea6818af5c1c726d6d278fd4979713 --account ../../demo-account.json --keystore ../../demo-key.json --network goerli-1 --watch 0xd3c21bcecceda1000000 0 0x0334863e3e851de87fb4b6b6113aa2a6b40ea20f22dbec55536e4eac912206fc @@ -146,240 +155,287 @@ NOTE: The deployed address received will differ for every user. Retain this addr Well done! The Cairo ERC20 smart contract has been deployed successfully on Starknet. -## Installing the Starknet React Library +## Setting Up a New React Project -With the contract in place, initiate the development of the web application. Begin by incorporating the Starknet React library: +With the contract in place, initiate the development of the web application. Begin by +setting up our react project. To do this, Nextjs framework provides the `create-next-app` script that streamlines the setup of a Nextjs application: ```bash -npm add @starknet-react/core +npx create-next-app@latest erc20_web --use-npm +✔ Would you like to use TypeScript? … Yes +✔ Would you like to use ESLint? … Yes +✔ Would you like to use Tailwind CSS? … Yes +✔ Would you like to use `src/` directory? … Yes +✔ Would you like to use App Router? (recommended) … Yes +✔ Would you like to customize the default import alias (@/*)? … No ``` -Post-installation, confirm the version of the Starknet React library: +Then, you should see something like this: ```bash -npm list @starknet-react/core -``` +Creating a new Next.js app in /home/kali/cairo/erc20_web. +Using npm. +Initializing project with template: app-tw +Installing dependencies: +- react +- react-dom +- next -The output should display the installed version, such as `@starknet-react/core@1.0.4`. +... [shortened for brevity] -## Setting Up a New React Project +Initialized a git repository. +Success! Created erc20_web at /home/kali/cairo/erc20_web +``` + +## Installing the Starknet.js Library -Starknet React library provides the `create-starknet` script that streamlines the setup of a Starknet application using TypeScript: +Now, let's install the starknet.js and recommended get-starknet (manage wallet connections) libraries: ```bash -npx create-starknet erc20_web --use-npm +cd erc20_web +npm install get-starknet ``` -Once set up, make modifications to `erc20_web/index.tsx` by replacing its content with the following code: +You should see something like this: -```typescript -import Head from 'next/head' -import { useBlock } from '@starknet-react/core' -import WalletBar from '../components/WalletBar' -import { BlockTag } from 'starknet'; +```bash +added 3 packages, changed 1 package, and audited 1549 packages in 7s +... [shortened for brevity] +Run `npm audit` for details. +``` -export default function Home() { - const { data, isLoading, isError } = useBlock({ - refetchInterval: 3000, - blockIdentifier: BlockTag.latest, - }) - return ( - <> - - Create Starknet - - - - -
-

- A basic web3 example with Starknet  -

-
- {isLoading - ? 'Loading...' - : isError - ? 'Error while fetching the latest block hash' - : `Latest block hash: ${data?.block_hash}`} -
- -
- - ) -} +Install starknetJS: + +```bash +npm install starknet ``` -To launch the web3 application: +You should see something like this: ```bash -cd erc20_web/ -npm run dev +added 18 packages, and audited 1546 packages in 6s +... [shortened for brevity] +Run `npm audit` for details. ``` -NOTE: Observe the server port that appears during launch. This will be useful for subsequent testing. +Post-installation, confirm the version of the Starknet.js library: -## Enhancing Your React Application with Additional Features +```bash +npm list starknet -To enhance the app's functionality, create two components for balance and transfer. Subsequently, update the `Wallet.tsx` file to incorporate the new features: +npm list get-starknet +``` -Basic Dapp ERC20 React Files +The output should display the installed version, such as `starknet@5.19.5` and `get-starknet@3.0.1`. -### Balance Component +## Building our Project -Design a balance component inside `components/Balance.tsx` and integrate the following code: +Once set up, make modifications to `erc20_web/src/app/layout.tsx` by replacing its content with the following code: ```typescript -import { useAccount, useContractRead } from "@starknet-react/core"; -import erc20ABI from '../assets/erc20.json'; - -function Balance() { - const { address } = useAccount(); - const { data, isLoading, error, refetch } = useContractRead({ - address: '0x001892d81e09cb2c2005f0112891dacb92a6f8ce571edd03ed1f3e549abcf37f', - abi: erc20ABI, - functionName: 'balance_of', - args: [address], - watch: false - }); - - if (isLoading) return Loading...; - if (error) return Error: {JSON.stringify(error)}; +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'Create Next App', + description: 'Generated by create next app', +} +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { return ( -
-

Balance:

-

{data?data.toString(): 0}

-

-
-
- ); + + {children} + + ) } -export default Balance; ``` -NOTE: Replace the address with the address of your deployed contract. +Now, edit `erc20_web/src/app/page.tsx` and replace its content with the following code: -### Transfer Component +```typescript +import Head from "next/head"; +import App from "../components/App"; -Craft a transfer component in `components/Transfer.tsx` and embed the subsequent code: +export default function Home() { -```typescript -import { useAccount, useContractWrite } from "@starknet-react/core"; -import React, { useState, useMemo } from "react"; - -function Transfer() { - const { address } = useAccount(); - const [count] = useState(1); - const [recipient, setRecipient] = useState('0x'); - const [amount, setAmount] = useState('1000000000000000000'); - - const calls = useMemo(() => { - const tx = { - contractAddress: '0x001892d81e09cb2c2005f0112891dacb92a6f8ce571edd03ed1f3e549abcf37f', - entrypoint: 'transfer', - calldata: [recipient, amount, 0] - }; - return Array(count).fill(tx); - }, [address, count, recipient, amount]); - - const { write } = useContractWrite({ calls }); - - return ( - <> -

Transfer:

-

- Recipient: - setRecipient(e.target.value)} /> -

-

- Amount (default: 1 MKT with 18 decimals): - setAmount(e.target.value)} /> -

-

-
- - ); + return ( + <> + + Homepage + + +
+

A basic web3 example with StarknetJS

+ +
+ + ); } - -export default Transfer; ``` -NOTE: Replace contractAddress with the address of your deployed contract. - -### Updating the Wallet Component +## Enhancing Your React Application with Additional Features -Proceed to modify the `components/Wallet.tsx` file. Replace any existing content with the following enhanced code: +To enhance the app's functionality, create one component (`erc20_web/src/components/App.tsx`) for balance and transfer with the following code. ```typescript -import { useAccount, useConnectors } from '@starknet-react/core' -import { useMemo } from 'react' -import Balance from '../components/Balance' -import Transfer from '../components/Transfer' +'use client'; +import { useState, useMemo } from "react" +import { connect, disconnect } from "get-starknet" +import { Contract, Provider, SequencerProvider, constants } from "starknet" + +const contractAddress = "0x001892d81e09cb2c2005f0112891dacb92a6f8ce571edd03ed1f3e549abcf37f" + +function App() { + const [provider, setProvider] = useState({} as Provider) + const [address, setAddress] = useState('') + const [currentBlockHash, setCurrentBlockHash] = useState('') + const [balance, setBalance] = useState('') + const [isConnected, setIsConnected] = useState(false) + const [recipient, setRecipient] = useState('0x'); + const [amount, setAmount] = useState('1000000000000000000'); + + const disconnectWallet = async () => { + try { + await disconnect({ clearLastWallet: true }) + setProvider({} as Provider) + setAddress('') + setIsConnected(false) + } + catch (error: any) { + alert(error.message) + } + } + + const connectWallet = async () => { + try { + const starknet = await connect() + if (!starknet) throw new Error("Failed to connect to wallet.") + await starknet.enable({ starknetVersion: "v5" }) + setProvider(starknet.account) + setAddress(starknet.selectedAddress || '') + setIsConnected(true) + } + catch (error: any) { + alert(error.message) + } + } + + const checkBalance = async () => { + try { + // initialize contract using abi, address and provider + const { abi: testAbi } = await provider.getClassAt(contractAddress); + if (testAbi === undefined) { throw new Error("no abi.") }; + const contract = new Contract(testAbi, contractAddress, provider) + // make contract call + const data = await contract.balance_of(address) + setBalance(data.toString()) + } + catch (error: any) { + alert(error.message) + } + } + + const transfer = async () => { + try { + // initialize contract using abi, address and provider + const { abi: testAbi } = await provider.getClassAt(contractAddress); + if (testAbi === undefined) { throw new Error("no abi.") }; + const contract = new Contract(testAbi, contractAddress, provider) + // make contract call + await contract.transfer(recipient, amount) + } + catch (error: any) { + alert(error.message) + } + } + + const current_block_hash = async () => { + try { + const provider1 = new SequencerProvider({ baseUrl: constants.BaseUrl.SN_GOERLI }); -function WalletConnected() { - const { address } = useAccount(); - const { disconnect } = useConnectors(); + const block = await provider1.getBlock("latest"); // <- Get latest block + setCurrentBlockHash(block.block_hash); + } + catch (error: any) { + alert(error.message) + } + } + + current_block_hash() const shortenedAddress = useMemo(() => { - if (!address) return ''; - return `${address.slice(0, 6)}...${address.slice(-4)}`; - }, [address]); + if (!isConnected) return '' + return `${address.slice(0, 6)}...${address.slice(-4)}` + }, [isConnected, address]) - return ( -
- Connected: {shortenedAddress} -

-
- - -
- ); -} + const handleRecipientChange = (event: React.ChangeEvent) => { + setRecipient(event.target.value); + }; -function ConnectWallet() { - const { connectors, connect } = useConnectors(); + const handleAmountChange = (event: React.ChangeEvent) => { + setAmount(event.target.value); + }; return (
- Select a wallet: -

- {connectors.map((connector) => ( - - ))} -

+

Latest block hash: {currentBlockHash}

+ {isConnected ? +
+ Connected: {shortenedAddress} +

+
+

Balance.

+

{balance}

+

+
+

Transfer.

+

Recipient: + +

+

Amount (default 1 MKT with 18 decimals): + +

+

+ +

+
+
: +
+ Choose a wallet: +

+ +

+
+ }
); } -export default function WalletBar() { - const { address } = useAccount(); - - return address ? : ; -} +export default App; ``` -This updated code refines the Wallet component to offer a more interactive experience for users intending to connect or manage their wallets. +Finally, launch the web3 application: -## Finalizing the MKT Token Application - -To finalize the application setup, we need the ABI file for the MKT token. Follow the steps below to generate and integrate it: - -1. At the root of your project, create a new directory named `assets/`. -2. Inside the `assets/` directory, create an empty JSON file named `erc20.json`. -3. Go back to your ERC20 Cairo project folder and locate the `erc20/target/erc20_erc20_sierra.json` file. - -ABI Original - -4. Extract the ABI definition (ensuring you include the square brackets) and integrate it into the previously created `assets/erc20.json` file. - -ABI Updated +```bash +cd erc20_web/ +npm run dev +``` -Well done! The basic MKT token application is now operational locally. Access it via `http://localhost:3000` or the port noted from earlier server setup. The app allows users to connect their wallets, review their balances, and perform token transfers. +Congratulations, you have your starknetjs web3 application. Now connect your wallet in goerli testnet, check your balance and transfer MKT tokens to your friends: -Localhost +Localhost ## Deploying Your Project Online @@ -393,20 +449,20 @@ To share your application with friends and allow them to check their balances an ```bash cd erc20_web/ npm i -g vercel -vercel init ``` 3. Authenticate your Vercel account: ```bash vercel login +Continue with Email (or select your preferent login method) ``` After entering your email, check your inbox and click on the "Verify" button. -Vercel login +Vercel login -Vercel verify +Vercel verify On successful verification, you'll receive a confirmation in the console. @@ -414,6 +470,13 @@ On successful verification, you'll receive a confirmation in the console. ```bash vercel link +? Set up “~/cairo/erc20_web”? [Y/n] y +? Which scope should contain your project? (just press enter) +? Link to existing project? [y/N] n +? What’s your project’s name? erc20-web +? In which directory is your code located? ./ +? Want to modify these settings? [y/N] n +✅ Linked erc20-web (created .vercel) ``` 5. Upload it: @@ -426,36 +489,36 @@ vercel ```bash vercel --prod +✅ Production: https://erc20-ch3cn791b-devnet0x-gmailcom.vercel.app [1s] ``` -Congratulations! Your MKT token web3 application is now accessible to everyone. +Check your production URL and congratulations! Your MKT token web3 application is now accessible to everyone. -Vercel publication +Vercel publication Engage with your app by: - Connecting your wallet: -Vercel publication 2 +Vercel publication 2 - Checking your balance: -Vercel publication 3 +Vercel publication 3 - Transferring tokens: -Vercel publication 4 +Vercel publication 4 ## Wrapping Up -Throughout this tutorial, you've walked through the steps to craft a web3 application using React and Starknet Cairo. This application, complete with an ERC20 smart contract, offers a modern web interface for user interaction. Here's a snapshot of your achievements: +Throughout this tutorial, you've walked through the steps to craft a web3 application using React, StarknetJS and Cairo. This application, complete with an ERC20 smart contract, offers a modern web interface for user interaction. Here's a snapshot of your achievements: - **Project Initialization**: Set up a Starknet project with Scarb and incorporated OpenZeppelin libraries. -- **Crafting the ERC20 Contract**: Developed an ERC20 token using Cairo, enriched with functionalities like balance checks and token transfers. This was then compiled and launched on the Starknet network. -- **React Application**: Built a React application powered by Starknet React, featuring components dedicated to balance inquiries and token transactions. +- **Crafting the ERC20 Contract**: Developed an ERC20 token using Cairo, enriched with functionalities like balance checks and token transfers. This was then compiled and launched on the Starknet network. -- **ABI Creation**: Produced the ABI for the MKT token, a critical component to liaise with the contract. +- **React Application**: Built a React application powered by StarknetJS, featuring components dedicated to balance inquiries and token transactions. - **Online Deployment**: Brought your application to a wider audience by deploying it on Vercel. This empowered users to connect their wallets, scrutinize their balances, and execute token transactions. diff --git a/src/ch02-07-01-examples.md b/src/ch02-07-01-examples.md index 9186f449f..6f58c9410 100644 --- a/src/ch02-07-01-examples.md +++ b/src/ch02-07-01-examples.md @@ -1,6 +1,6 @@ # Examples -In this subchapter, readers will find practical examples demonstrating the usage of both `starknet-js` and `starknet-react`. It provides insight into real-world applications and serves as a guide for developers to understand and implement these tools effectively. +In this subchapter, readers will find practical examples demonstrating the usage of `starknet-js`. It provides insight into real-world applications and serves as a guide for developers to understand and implement these tools effectively. We value the contribution of our developer community: diff --git a/src/ch02-08-01-01-erc20-ui.md b/src/ch02-08-01-01-erc20-ui.md new file mode 100644 index 000000000..db83ff63a --- /dev/null +++ b/src/ch02-08-01-01-erc20-ui.md @@ -0,0 +1,470 @@ +# ERC-20 UI + +This guide offers steps to build an ERC20 smart contract using Cairo and to incorporate it within a React web application with Starknet React. Readers will: + +- Understand how to implement the ERC20 interface +- Learn how to deploy contracts on the Starknet network +- Discover ways to engage with contracts within a React application +- Design their own ERC20 token and initiate it on Starknet + +A prerequisite for this guide is a foundational understanding of both the Cairo programming language and ReactJS. Additionally, ensure Node.js and NPM are installed on the system. + +The example will walk through creating an ERC20 token named MKT and crafting a web3 interface for functionalities such as balance verification and token transfer. + +Basic Dapp ERC20 + +Throughout this guide, the following tools and libraries will be utilized: + +- 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 + +## Initiating a New Starknet Project + +Begin by establishing a new Starknet project named "erc20" using Scarb: + +```bash +mkdir erc20 +cd erc20 +scarb init --name erc20 +``` + +Subsequently, update the Scarb.toml to include the essential OpenZeppelin libraries. Post edits, the Scarb.toml should appear as: + +```toml +[package] +name = "erc20" +version = "0.1.0" + +# For more keys and definitions, visit https://docs.swmansion.com/scarb/docs/reference/manifest.html + +[dependencies] +starknet = ">=2.2.0" +openzeppelin = { git = "https://github.com/OpenZeppelin/cairo-contracts.git", tag = "v0.7.0" } + +[[target.starknet-contract]] +``` + +## Implementing the ERC20 Token + +Begin by creating a new file named `src/erc20.cairo`. In this file, the ERC20 token named MKT, along with its associated functions, will be defined: + +```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) + } + } +} +``` + +Basic Dapp ERC20 + +Now edit `src/lib.cairo` and replace the content with: + +```rust +mod erc20; +``` + +Basic Dapp ERC20 + +Upon completing your contract, proceed to compile it using Scarb: + +```bash +scarb build +``` + +Subsequent to the compilation, declare the smart contract on the Starknet testnet: + +```bash +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 +``` + +The output should appear similar to: + +```bash +Enter keystore password: +Declaring Cairo 1 class: 0x04940154eae35788e899ceb0ef2794eaa5ea6818af5c1c726d6d278fd4979713 +... [shortened for brevity] +Class hash declared: 0x04940154eae35788e899ceb0ef2794eaa5ea6818af5c1c726d6d278fd4979713 +``` + +In cases where no modifications have been made to the provided contract, a notification will indicate that the contract has previously been declared on Starknet: + +```bash +Enter keystore password: +Not declaring class as it's already declared. Class hash: 0x04940154eae35788e899ceb0ef2794eaa5ea6818af5c1c726d6d278fd4979713 +``` + +## Deploying the ERC20 Contract + +Proceed to deploy the MKT Token using Starkli. Provide these arguments for successful deployment: + +- `Initial mint`: Mint 1,000,000 tokens. Given that the MKT token comprises 18 decimals (a standard of OpenZeppelin), the input required is 1,000,000 \* 10^18 or 0xd3c21bcecceda1000000. Due to the contract's expectation of a u256 mint value, provide both low and high values: 0xd3c21bcecceda1000000 and 0 respectively. +- `Receiver address`: Use a preferred address. In this example: 0x0334863e3e851de87fb4b6b6113aa2a6b40ea20f22dbec55536e4eac912206fc + +```bash +starkli deploy 0x04940154eae35788e899ceb0ef2794eaa5ea6818af5c1c726d6d278fd4979713 --account ../../demo-account.json --keystore ../../demo-key.json --network goerli-1 --watch 0xd3c21bcecceda1000000 0 0x0334863e3e851de87fb4b6b6113aa2a6b40ea20f22dbec55536e4eac912206fc +``` + +The output should appear similar to: + +```bash +Enter keystore password: +... [shortened for brevity] +Contract deployed: 0x001892d81e09cb2c2005f0112891dacb92a6f8ce571edd03ed1f3e549abcf37f +``` + +NOTE: The deployed address received will differ for every user. Retain this address, as it will replace instances in subsequent TypeScript files to match the specific contract address. + +Well done! The Cairo ERC20 smart contract has been deployed successfully on Starknet. + +## Installing the Starknet React Library + +With the contract in place, initiate the development of the web application. Begin by incorporating the Starknet React library: + +```bash +npm add @starknet-react/core +``` + +Post-installation, confirm the version of the Starknet React library: + +```bash +npm list @starknet-react/core +``` + +The output should display the installed version, such as `@starknet-react/core@1.0.4`. + +## Setting Up a New React Project + +Starknet React library provides the `create-starknet` script that streamlines the setup of a Starknet application using TypeScript: + +```bash +npx create-starknet erc20_web --use-npm +``` + +Once set up, make modifications to `erc20_web/index.tsx` by replacing its content with the following code: + +```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 ( + <> + + Create Starknet + + + + +
+

+ A basic web3 example with Starknet  +

+
+ {isLoading + ? 'Loading...' + : isError + ? 'Error while fetching the latest block hash' + : `Latest block hash: ${data?.block_hash}`} +
+ +
+ + ) +} +``` + +To launch the web3 application: + +```bash +cd erc20_web/ +npm run dev +``` + +NOTE: Observe the server port that appears during launch. This will be useful for subsequent testing. + +## Enhancing Your React Application with Additional Features + +To enhance the app's functionality, create two components for balance and transfer. Subsequently, update the `Wallet.tsx` file to incorporate the new features: + +Basic Dapp ERC20 React Files + +### Balance Component + +Design a balance component inside `components/Balance.tsx` and integrate the following code: + +```typescript +import { useAccount, useContractRead } from "@starknet-react/core"; +import erc20ABI from '../assets/erc20.json'; + +function Balance() { + const { address } = useAccount(); + const { data, isLoading, error, refetch } = useContractRead({ + address: '0x001892d81e09cb2c2005f0112891dacb92a6f8ce571edd03ed1f3e549abcf37f', + abi: erc20ABI, + functionName: 'balance_of', + args: [address], + watch: false + }); + + if (isLoading) return Loading...; + if (error) return Error: {JSON.stringify(error)}; + + return ( +
+

Balance:

+

{data?data.toString(): 0}

+

+
+
+ ); +} + +export default Balance; +``` + +NOTE: Replace the address with the address of your deployed contract. + +### Transfer Component + +Craft a transfer component in `components/Transfer.tsx` and embed the subsequent code: + +```typescript +import { useAccount, useContractWrite } from "@starknet-react/core"; +import React, { useState, useMemo } from "react"; + +function Transfer() { + const { address } = useAccount(); + const [count] = useState(1); + const [recipient, setRecipient] = useState('0x'); + const [amount, setAmount] = useState('1000000000000000000'); + + const calls = useMemo(() => { + const tx = { + contractAddress: '0x001892d81e09cb2c2005f0112891dacb92a6f8ce571edd03ed1f3e549abcf37f', + entrypoint: 'transfer', + calldata: [recipient, amount, 0] + }; + return Array(count).fill(tx); + }, [address, count, recipient, amount]); + + const { write } = useContractWrite({ calls }); + + return ( + <> +

Transfer:

+

+ Recipient: + setRecipient(e.target.value)} /> +

+

+ Amount (default: 1 MKT with 18 decimals): + setAmount(e.target.value)} /> +

+

+
+ + ); +} + +export default Transfer; +``` + +NOTE: Replace contractAddress with the address of your deployed contract. + +### Updating the Wallet Component + +Proceed to modify the `components/Wallet.tsx` file. Replace any existing content with the following enhanced code: + +```typescript +import { useAccount, useConnectors } from '@starknet-react/core' +import { useMemo } from 'react' +import Balance from '../components/Balance' +import Transfer from '../components/Transfer' + +function WalletConnected() { + const { address } = useAccount(); + const { disconnect } = useConnectors(); + + const shortenedAddress = useMemo(() => { + if (!address) return ''; + return `${address.slice(0, 6)}...${address.slice(-4)}`; + }, [address]); + + return ( +
+ Connected: {shortenedAddress} +

+
+ + +
+ ); +} + +function ConnectWallet() { + const { connectors, connect } = useConnectors(); + + return ( +
+ Select a wallet: +

+ {connectors.map((connector) => ( + + ))} +

+
+ ); +} + +export default function WalletBar() { + const { address } = useAccount(); + + return address ? : ; +} +``` + +This updated code refines the Wallet component to offer a more interactive experience for users intending to connect or manage their wallets. + +## Finalizing the MKT Token Application + +To finalize the application setup, we need the ABI file for the MKT token. Follow the steps below to generate and integrate it: + +1. At the root of your project, create a new directory named `assets/`. +2. Inside the `assets/` directory, create an empty JSON file named `erc20.json`. +3. Go back to your ERC20 Cairo project folder and locate the `erc20/target/erc20_erc20_sierra.json` file. + +ABI Original + +4. Extract the ABI definition (ensuring you include the square brackets) and integrate it into the previously created `assets/erc20.json` file. + +ABI Updated + +Well done! The basic MKT token application is now operational locally. Access it via `http://localhost:3000` or the port noted from earlier server setup. The app allows users to connect their wallets, review their balances, and perform token transfers. + +Localhost + +## Deploying Your Project Online + +To share your application with friends and allow them to check their balances and transfer tokens, publish your app online. Vercel offers a straightforward way to do this: + +### Set Up Vercel + +1. Register for an account at [Vercel Signup](https://vercel.com/signup). +2. Install Vercel in your web application folder (`erc20_web`): + +```bash +cd erc20_web/ +npm i -g vercel +vercel init +``` + +3. Authenticate your Vercel account: + +```bash +vercel login +``` + +After entering your email, check your inbox and click on the "Verify" button. + +Vercel login + +Vercel verify + +On successful verification, you'll receive a confirmation in the console. + +4. Link your project to Vercel: + +```bash +vercel link +``` + +5. Upload it: + +```bash +vercel +``` + +6. Publish your project: + +```bash +vercel --prod +``` + +Congratulations! Your MKT token web3 application is now accessible to everyone. + +Vercel publication + +Engage with your app by: + +- Connecting your wallet: + +Vercel publication 2 + +- Checking your balance: + +Vercel publication 3 + +- Transferring tokens: + +Vercel publication 4 + +## Wrapping Up + +Throughout this tutorial, you've walked through the steps to craft a web3 application using React and Starknet Cairo. This application, complete with an ERC20 smart contract, offers a modern web interface for user interaction. Here's a snapshot of your achievements: + +- **Project Initialization**: Set up a Starknet project with Scarb and incorporated OpenZeppelin libraries. +- **Crafting the ERC20 Contract**: Developed an ERC20 token using Cairo, enriched with functionalities like balance checks and token transfers. This was then compiled and launched on the Starknet network. + +- **React Application**: Built a React application powered by Starknet React, featuring components dedicated to balance inquiries and token transactions. + +- **ABI Creation**: Produced the ABI for the MKT token, a critical component to liaise with the contract. + +- **Online Deployment**: Brought your application to a wider audience by deploying it on Vercel. This empowered users to connect their wallets, scrutinize their balances, and execute token transactions. + +The insights you've gathered from this tutorial lay a solid groundwork for creating intricate web3 applications. You're now equipped with the prowess to craft more intricate decentralized applications and smart contracts. The vast expanse of decentralized finance and blockchain is ripe for your innovative inputs. Dive in and happy coding! diff --git a/src/ch02-08-01-examples.md b/src/ch02-08-01-examples.md new file mode 100644 index 000000000..f1363ab8a --- /dev/null +++ b/src/ch02-08-01-examples.md @@ -0,0 +1,10 @@ +# Examples + +In this subchapter, readers will find practical examples demonstrating the usage of `starknet-react`. It provides insight into real-world applications and serves as a guide for developers to understand and implement these tools effectively. + +We value the contribution of our developer community: + +- We encourage developers to contribute additional examples. +- Please inform us if you identify any mistakes or inaccuracies. + +Your insights and feedback are instrumental in making this resource more comprehensive and accurate. diff --git a/src/img/ch02-basic-dapp-erc20_js.png b/src/img/ch02-basic-dapp-erc20_js.png new file mode 100644 index 000000000..af0d055b2 Binary files /dev/null and b/src/img/ch02-basic-dapp-erc20_js.png differ diff --git a/src/img/ch02-basic-dapp-erc20_lib.png b/src/img/ch02-basic-dapp-erc20_lib.png new file mode 100644 index 000000000..644c69ef0 Binary files /dev/null and b/src/img/ch02-basic-dapp-erc20_lib.png differ diff --git a/src/img/ch02-basic-dapp-erc20_lib_js.png b/src/img/ch02-basic-dapp-erc20_lib_js.png new file mode 100644 index 000000000..644c69ef0 Binary files /dev/null and b/src/img/ch02-basic-dapp-erc20_lib_js.png differ diff --git a/src/img/ch02-basic-dapp-localhost_js.png b/src/img/ch02-basic-dapp-localhost_js.png new file mode 100644 index 000000000..0761e34da Binary files /dev/null and b/src/img/ch02-basic-dapp-localhost_js.png differ diff --git a/src/img/ch02-basic-dapp-pub1_js.png b/src/img/ch02-basic-dapp-pub1_js.png new file mode 100644 index 000000000..f1051a1e1 Binary files /dev/null and b/src/img/ch02-basic-dapp-pub1_js.png differ diff --git a/src/img/ch02-basic-dapp-pub2_js.png b/src/img/ch02-basic-dapp-pub2_js.png new file mode 100644 index 000000000..fbe2efe5d Binary files /dev/null and b/src/img/ch02-basic-dapp-pub2_js.png differ diff --git a/src/img/ch02-basic-dapp-pub3_js.png b/src/img/ch02-basic-dapp-pub3_js.png new file mode 100644 index 000000000..342564ebf Binary files /dev/null and b/src/img/ch02-basic-dapp-pub3_js.png differ diff --git a/src/img/ch02-basic-dapp-pub4_js.png b/src/img/ch02-basic-dapp-pub4_js.png new file mode 100644 index 000000000..857c5a717 Binary files /dev/null and b/src/img/ch02-basic-dapp-pub4_js.png differ diff --git a/src/img/ch02-basic-dapp-screenshot_js.png b/src/img/ch02-basic-dapp-screenshot_js.png new file mode 100644 index 000000000..12ac85eee Binary files /dev/null and b/src/img/ch02-basic-dapp-screenshot_js.png differ diff --git a/src/img/ch02-basic-dapp-vercel-login_js.png b/src/img/ch02-basic-dapp-vercel-login_js.png new file mode 100644 index 000000000..d14cd6814 Binary files /dev/null and b/src/img/ch02-basic-dapp-vercel-login_js.png differ diff --git a/src/img/ch02-basic-dapp-vercel-verify_js.png b/src/img/ch02-basic-dapp-vercel-verify_js.png new file mode 100644 index 000000000..6eea1262e Binary files /dev/null and b/src/img/ch02-basic-dapp-vercel-verify_js.png differ