From 2ec27bdb137a2339921834e94acb5e647e744f03 Mon Sep 17 00:00:00 2001 From: Nadai2010 Date: Tue, 4 Feb 2025 11:28:29 +0000 Subject: [PATCH 1/4] Update recipie MultiWriteFeature --- docs/recipes/MultiWriteFeature.md | 97 +++++++++++++++++-------------- 1 file changed, 53 insertions(+), 44 deletions(-) diff --git a/docs/recipes/MultiWriteFeature.md b/docs/recipes/MultiWriteFeature.md index 79d2b8b..cb43302 100644 --- a/docs/recipes/MultiWriteFeature.md +++ b/docs/recipes/MultiWriteFeature.md @@ -18,25 +18,29 @@ This documentation will walk through the code and steps necessary to create a bu Here is full implementation of the mult-write feature: ```tsx title="components/MultiContractInteraction.tsx" +"use client"; + import { useState } from "react"; +import { useScaffoldContract } from "~~/hooks/scaffold-stark/useScaffoldContract"; import { useScaffoldMultiWriteContract } from "~~/hooks/scaffold-stark/useScaffoldMultiWriteContract"; -import { notification } from "~~/utils/scaffold-stark"; -export const MultiSetData = () => { - const [name, setName] = useState(""); - const [age, setAge] = useState(0); +const MultiSetData = () => { + const [inputAmount, setInputAmount] = useState(0n); + const [greeting, setGreeting] = useState(""); + + const { data: YourContract } = useScaffoldContract({ contractName: "YourContract" }); const { sendAsync, isPending } = useScaffoldMultiWriteContract({ calls: [ { - contractName: "ProfileContract", - functionName: "setName", - args: [name], + contractName: "Eth", + functionName: "approve", + args: [YourContract?.address, BigInt(inputAmount)], }, { - contractName: "ProfileContract", - functionName: "setAge", - args: [age], + contractName: "YourContract", + functionName: "set_greeting", + args: [greeting, BigInt(inputAmount)], }, ], }); @@ -44,10 +48,8 @@ export const MultiSetData = () => { const handleSetData = async () => { try { await sendAsync(); - notification("Multi-write successful!", "success"); } catch (e) { console.error("Error in multi-write", e); - notification("Multi-write failed.", "error"); } }; @@ -55,15 +57,17 @@ export const MultiSetData = () => {
setName(e.target.value)} + onChange={e => setGreeting(e.target.value)} /> setAge(Number(e.target.value))} + onChange={e => { + setInputAmount(BigInt(Number(e.target.value) * 10 ** 18)); + }} />
); }; + +export default MultiSetData; ``` @@ -103,26 +109,26 @@ import { notification } from "~~/utils/scaffold-stark"; - Use the `useState` hook to track user inputs, `name` and `age`. ```tsx title="components/MultiContractInteraction.tsx" -const [name, setName] = useState(""); -const [age, setAge] = useState(0); +const [inputAmount, setInputAmount] = useState(0n); +const [greeting, setGreeting] = useState(""); ``` ### Step 4: Configure the [`useScaffoldMultiWriteContract`](https://github.com/Scaffold-Stark/scaffold-stark-2/blob/main/packages/nextjs/hooks/scaffold-stark/useScaffoldMultiWriteContract.ts) Hook -- Configure the hook with the necessary contract calls. Here, we call the `setName` and `setAge` functions of `ProfileContract` in sequence. +- Configure the hook with the necessary contract calls. Here, we call the `setGreeting` and `setInputAmount` functions of `YourContract` and `Eth` in sequence. ```tsx title="components/MultiContractInteraction.tsx" const { sendAsync, isPending } = useScaffoldMultiWriteContract({ calls: [ { - contractName: "ProfileContract", - functionName: "setName", - args: [name], + contractName: "Eth", + functionName: "approve", + args: [YourContract?.address, BigInt(inputAmount)], }, { - contractName: "ProfileContract", - functionName: "setAge", - args: [age], + contractName: "YourContract", + functionName: "set_greeting", + args: [greeting, BigInt(inputAmount)], }, ], }); @@ -148,27 +154,30 @@ const handleSetData = async () => { ### Step 6: Create the UI -- Add inputs for `name` and `age`, and a button to submit the data. +- Add inputs for `gretting` and `inputAmount`, and a button to submit the data. - Disable the button while the transaction is pending. ```tsx return ( -
- setName(e.target.value)} - /> - setAge(Number(e.target.value))} - /> - -
-); +
+ + greeting(e.target.value)} + /> + { + setInputAmount(BigInt(Number(e.target.value) * 10 ** 18)); + /> + +
+ ); +}; ``` From 0b78cc68816c04504bc6c7074a272c3b2d9ed351 Mon Sep 17 00:00:00 2001 From: Nadai2010 Date: Tue, 4 Feb 2025 11:45:15 +0000 Subject: [PATCH 2/4] Add transfer in MultiWrite --- docs/recipes/MultiWriteFeature.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/recipes/MultiWriteFeature.md b/docs/recipes/MultiWriteFeature.md index cb43302..aeab1b2 100644 --- a/docs/recipes/MultiWriteFeature.md +++ b/docs/recipes/MultiWriteFeature.md @@ -37,6 +37,11 @@ const MultiSetData = () => { functionName: "approve", args: [YourContract?.address, BigInt(inputAmount)], }, + { + contractName: "Eth", + functionName: "transfer", + args: [YourContract?.address, BigInt(inputAmount)], + }, { contractName: "YourContract", functionName: "set_greeting", @@ -106,7 +111,7 @@ import { notification } from "~~/utils/scaffold-stark"; ### Step 3: Set Up State Variables -- Use the `useState` hook to track user inputs, `name` and `age`. +- Use the `useState` hook to track user inputs, `greeting` and `inputAmount`. ```tsx title="components/MultiContractInteraction.tsx" const [inputAmount, setInputAmount] = useState(0n); @@ -125,6 +130,11 @@ const { sendAsync, isPending } = useScaffoldMultiWriteContract({ functionName: "approve", args: [YourContract?.address, BigInt(inputAmount)], }, + { + contractName: "Eth", + functionName: "transfer", + args: [YourContract?.address, BigInt(inputAmount)], + }, { contractName: "YourContract", functionName: "set_greeting", From f7f3e0b138837d7e0637de768bf5ceb3651aef4b Mon Sep 17 00:00:00 2001 From: Nadai2010 Date: Tue, 4 Feb 2025 12:26:04 +0000 Subject: [PATCH 3/4] Add Recipie in ReadUintFromContract with ETH balance and Gretting --- docs/recipes/ReadUintFromContract.md | 193 +++++++++++++-------------- 1 file changed, 90 insertions(+), 103 deletions(-) diff --git a/docs/recipes/ReadUintFromContract.md b/docs/recipes/ReadUintFromContract.md index 6d733c6..4db02c8 100644 --- a/docs/recipes/ReadUintFromContract.md +++ b/docs/recipes/ReadUintFromContract.md @@ -6,51 +6,57 @@ description: Learn how to read from contract functions which accept arguments / # Read a `uint` from a contract -This recipe demonstrates how to read data from contract functions and display it on the UI. We'll showcase an example that accepts some arguments (parameters), and another with no arguments at all. +This recipe demonstrates how to read data from contract functions and display it on the UI. We'll showcase an example that accepts arguments (parameters) and another with no arguments at all.
-Here is the full code, which we will be implementing in the guide below: +Here is the full code, which we will implement in the guide below: -```tsx title="components/GreetingsCount.tsx" -import { useAccount } from "@starknet-react/core"; +```tsx title="components/Greetings.tsx" +"use client"; + +import { useScaffoldContract } from "~~/hooks/scaffold-stark/useScaffoldContract"; import { useScaffoldReadContract } from "~~/hooks/scaffold-stark/useScaffoldReadContract"; -export const GreetingsCount = () => { - const { account: connectedAddress } = useAccount(); +const Greetings = () => { + const { data: YourContract } = useScaffoldContract({ contractName: "YourContract" }); - const { data: totalCounter, isLoading: isTotalCounterLoading } = useScaffoldReadContract({ + const { data: currentGreeting, isLoading: isCurrentGreetingLoading } = useScaffoldReadContract({ contractName: "YourContract", - functionName: "totalCounter", + functionName: "greeting", }); - const { data: connectedAddressCounter, isLoading: isConnectedAddressCounterLoading } = useScaffoldReadContract({ - contractName: "YourContract", - functionName: "userGreetingCounter", - args: [connectedAddress], // passing args to function + const { data: ethBalance, isLoading: isEthBalanceLoading } = useScaffoldReadContract({ + contractName: "Eth", + functionName: "balance_of", + args: [YourContract?.address], }); return ( -
-
-

Greetings Count

-
-

Total Greetings count:

- {isTotalCounterLoading ? ( +
+
+

Greetings

+
+

Balance ETH in YourContract:

+ {isEthBalanceLoading ? ( ) : ( -

{totalCounter ? totalCounter.toString() : 0}

+

{ethBalance ? (Number(ethBalance) / 10 ** 18).toFixed(6) : "0.000000"} ETH

)} -

Your Greetings count:

- {isConnectedAddressCounterLoading ? ( +
+
+

New Greeting:

+ {isCurrentGreetingLoading ? ( ) : ( -

{connectedAddressCounter ? connectedAddressCounter.toString() : 0}

+

{currentGreeting ? currentGreeting.toString() : "No greeting"}

)}
); }; + +export default Greetings; ```
@@ -61,135 +67,116 @@ export const GreetingsCount = () => { Begin by creating a new component in the "components" folder of your application. -```tsx title="components/GreetingsCount.tsx" -export const GreetingsCount = () => { +```tsx title="components/Greetings.tsx" +const Greetings = () => { return (
-

Total Greetings count:

-

Your Greetings count:

+

Balance ETH in YourContract:

+

New Greeting:

); }; +export default Greetings; ``` -### Step 2: Retrieve total greetings count +### Step 2: Retrieve New Greetings -Initialize the [useScaffoldReadContract](/hooks/useScaffoldReadContract) hook to read from the contract. This hook provides the `data` which contains the return value of the function. +Initialize the [`useScaffoldReadContract`](/hooks/useScaffoldReadContract) hook to read from the contract. This hook provides the `data` which contains the return value of the function. -```tsx title="components/GreetingsCount.tsx" +```tsx title="components/Greetings.tsx" import { useScaffoldReadContract } from "~~/hooks/scaffold-stark/useScaffoldReadContract"; -// highlight-end -export const GreetingsCount = () => { - // highlight-start - const { data: totalCounter } = useScaffoldReadContract({ +const Greetings = () => { + const { data: currentGreeting } = useScaffoldReadContract({ contractName: "YourContract", - functionName: "totalCounter", + functionName: "greeting", }); - // highlight-end return (
-

Total Greetings count:

- //highlight-start -

{totalCounter ? totalCounter.toString() : 0}

- //highlight-end -

Your Greetings count:

+

New Greeting:

+

{currentGreeting ? currentGreeting.toString() : "No greeting"}

); }; ``` -In the line `const {data: totalCounter} = useScaffoldReadContract({...})` we are using [destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) to assign `data` to a new name `totalCounter`. +In the line `const {data: currentGreeting} = useScaffoldReadContract({...})`, we use [destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) to extract the `data` field and rename it as `currentGreeting`. -In the contract, `totalCounter` returns an `uint` value, which is represented as a [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) in javascript and can be converted to a readable string using `.toString()`. +The contract function returns a `uint`, which is represented as a [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) in JavaScript. You can convert it to a readable string using `.toString()`. -### Step 3: Retrieve connected address greetings count +### Step 3: Retrieve ETH Balance in YourContract -We can get the connected address using the [useAccount](https://starknet-react.com/hooks/account/useaccount) hook and pass it to `args` key in the `useScaffoldReadContract` hook configuration. This will be used as an argument to read the contract function. +We can retrieve the ETH balance of the contract by first getting its address using `useScaffoldContract`. Then, we pass this address as an argument (`args`) to `useScaffoldReadContract`, which will call the contract function. -```tsx title="components/GreetingsCount.tsx" -import { useScaffoldReadContract } from "~~/hooks/scaffold-stark"; -//highlight-start -import { useAccount } from "@starknet-react/core"; -//highlight-end +```tsx title="components/Greetings.tsx" +import { useScaffoldContract } from "~~/hooks/scaffold-stark/useScaffoldContract"; +import { useScaffoldReadContract } from "~~/hooks/scaffold-stark/useScaffoldReadContract"; -export const GreetingsCount = () => { - //highlight-start - const { account: connectedAddress } = useAccount(); - //highlight-end +const Greetings = () => { + const { data: YourContract } = useScaffoldContract({ contractName: "YourContract" }); - const { data: totalCounter } = useScaffoldReadContract({ - contractName: "YourContract", - functionName: "totalCounter", + const { data: ethBalance } = useScaffoldReadContract({ + contractName: "Eth", + functionName: "balance_of", + args: [YourContract?.address], }); - //highlight-start - const { data: connectedAddressCounter } = useScaffoldReadContract({ - contractName: "YourContract", - functionName: "userGreetingCounter", - args: [connectedAddress], // passing args to function - }); - //highlight-end - return (
-

Total Greetings count:

-

{totalCounter ? totalCounter.toString() : 0}

-

Your Greetings count:

- //highlight-start -

{connectedAddressCounter ? connectedAddressCounter.toString() : 0}

- //highlight-end +

Balance ETH in YourContract:

+

{ethBalance ? (Number(ethBalance) / 10 ** 18).toFixed(6) : "0.000000"} ETH

); }; ``` -### Step 4: Bonus adding loading state +### Step 4: Handling Loading State -We can use `isLoading` returned from the [`useScaffoldReadContract`](/hooks/usescaffoldreadcontract) hook. This variable is set to `true` while fetching data from the contract. +We can use the `isLoading` flag returned from `useScaffoldReadContract` to show a loading spinner while fetching data from the contract. -```tsx title="components/GreetingsCount.tsx" +```tsx title="components/Greetings.tsx" +import { useScaffoldContract } from "~~/hooks/scaffold-stark/useScaffoldContract"; import { useScaffoldReadContract } from "~~/hooks/scaffold-stark/useScaffoldReadContract"; -import { useAccount } from "@starknet-react/core"; -export const GreetingsCount = () => { - const { account: connectedAddress } = useAccount(); +const Greetings = () => { + const { data: YourContract } = useScaffoldContract({ contractName: "YourContract" }); - // highlight-start - const { data: totalCounter, isLoading: isTotalCounterLoading } = useScaffoldReadContract({ - // highlight-end + const { data: currentGreeting, isLoading: isCurrentGreetingLoading } = useScaffoldReadContract({ contractName: "YourContract", - functionName: "totalCounter", + functionName: "greeting", }); - // highlight-start - const { data: connectedAddressCounter, isLoading: isConnectedAddressCounterLoading } = useScaffoldReadContract({ - // highlight-end - contractName: "YourContract", - functionName: "userGreetingCounter", - args: [connectedAddress], // passing args to function + const { data: ethBalance, isLoading: isEthBalanceLoading } = useScaffoldReadContract({ + contractName: "Eth", + functionName: "balance_of", + args: [YourContract?.address], }); return ( -
-

Total Greetings count:

- // highlight-start - {isTotalCounterLoading ? ( - - ) : ( -

{totalCounter ? totalCounter.toString() : 0}

- )} - // highlight-end -

Your Greetings count:

- // highlight-start - {isConnectedAddressCounterLoading ? ( - - ) : ( -

{connectedAddressCounter ? connectedAddressCounter.toString() : 0}

- )} - // highlight-end +
+
+

Greetings

+
+

Balance ETH in YourContract:

+ {isEthBalanceLoading ? ( + + ) : ( +

{ethBalance ? (Number(ethBalance) / 10 ** 18).toFixed(6) : "0.000000"} ETH

+ )} +
+
+

New Greeting:

+ {isCurrentGreetingLoading ? ( + + ) : ( +

{currentGreeting ? currentGreeting.toString() : "No greeting"}

+ )} +
+
); }; + +export default Greetings; ``` From e27b5c51be5b7f11f61cccaf7ea1a805284cf617 Mon Sep 17 00:00:00 2001 From: Nadai2010 Date: Wed, 5 Feb 2025 09:43:52 +0000 Subject: [PATCH 4/4] Add recipe in WriteToContractWriteAsyncButton --- docs/recipes/ReadUintFromContract.md | 2 +- .../WriteToContractWriteAsyncButton.md | 183 ++++++++---------- 2 files changed, 83 insertions(+), 102 deletions(-) diff --git a/docs/recipes/ReadUintFromContract.md b/docs/recipes/ReadUintFromContract.md index 4db02c8..5bb6252 100644 --- a/docs/recipes/ReadUintFromContract.md +++ b/docs/recipes/ReadUintFromContract.md @@ -65,7 +65,7 @@ export default Greetings; ### Step 1: Create a new Component -Begin by creating a new component in the "components" folder of your application. +Begin by creating a new component in the `components` folder of your application. ```tsx title="components/Greetings.tsx" const Greetings = () => { diff --git a/docs/recipes/WriteToContractWriteAsyncButton.md b/docs/recipes/WriteToContractWriteAsyncButton.md index c4e72c2..bd367fa 100644 --- a/docs/recipes/WriteToContractWriteAsyncButton.md +++ b/docs/recipes/WriteToContractWriteAsyncButton.md @@ -6,50 +6,48 @@ description: Learn how to create a button that executes the writeContractAsync f # Write to a Contract with `sendAsync` button using the `useScaffoldWriteContract` hook. -This recipe demonstrates how to create a button for contract interaction using the `useScaffoldWriteContract` hooks from the Scaffold-Stark 2 hooks. +This recipe demonstrates how to create a button for contract interaction using the `useScaffoldWriteContract` hook from Scaffold-Stark.
Here is the full code, which we will be implementing in the guide below: ```tsx title="components/ContractInteraction.tsx" +"use client"; import { useState } from "react"; import { useScaffoldWriteContract } from "~~/hooks/scaffold-stark/useScaffoldWriteContract"; -export const SetName = () => { - const [newName, setNewName] = useState(""); - +const SetGreeting = () => { + const [greeting, setGreeting] = useState(""); const { sendAsync, isPending } = useScaffoldWriteContract({ - calls: [ - { - contractName: "YourContract", - functionName: "setName", - args: [newName], - }, - ], + contractName: "YourContract", + functionName: "set_greeting", + args: [greeting, 0n], // `inputAmount` fixed at 0n }); - const handleSetName = async () => { + const handleSetGreeting = async () => { try { await sendAsync(); } catch (e) { - console.error("Error setting name", e); + console.error("Error setting greeting", e); } }; return ( - <> +
setNewName(e.target.value)} + onChange={e => setGreeting(e.target.value)} /> - - +
); }; + +export default SetGreeting; ```
@@ -58,158 +56,141 @@ export const SetName = () => { ### Step 1: Set Up Your Component -Create a new component in the "components" folder. The component will show a button that will allow users to interact with your smart contract. +Create a new component in the `components` folder. This component will display an input field and a button to interact with your smart contract. ```tsx title="components/ContractInteraction.tsx" -export const SetName = () => { +"use client"; + +const SetGreeting = () => { return ( - <> - - - +
+ + +
); }; + +export default SetGreeting; ``` -### Step 2: Initialize useScaffoldWriteContract hook +### Step 2: Initialize `useScaffoldWriteContract` Hook -Initialize the `useScaffoldWriteContract` hook. This hook provides the `sendAsync` function for sending transactions. We'll create a `handleSetName` function in which we'll call and pass parameters to `sendAsync` required to perform contract interaction. +Now we'll add state management and initialize the hook for contract interaction: -```tsx -// highlight-start +```tsx title="components/ContractInteraction.tsx" +"use client"; import { useState } from "react"; import { useScaffoldWriteContract } from "~~/hooks/scaffold-stark/useScaffoldWriteContract"; -// highlight-end - -export const SetName = () => { - // highlight-start - const [newName, setNewName] = useState(""); - // highlight-end - // highlight-start +const SetGreeting = () => { + const [greeting, setGreeting] = useState(""); const { sendAsync } = useScaffoldWriteContract({ - calls: [ - { - contractName: "YourContract", - functionName: "setName", - args: [newName], - }, - ], + contractName: "YourContract", + functionName: "set_greeting", + args: [greeting, 0n], // `inputAmount` fixed at 0n }); - // highlight-end - // highlight-start - const handleSetName = async () => { + const handleSetGreeting = async () => { try { await sendAsync(); } catch (e) { - console.error("Error setting name", e); + console.error("Error setting greeting", e); } }; - // highlight-end return ( - <> - - - +
+ + +
); }; + +export default SetGreeting; ``` -### Step 3: Add input change logic and send transaction when users click the button +### Step 3: Add Input Change Logic and Connect Button -Wire up the input field to update the `newName` state when the user types in a new name and call the `handleSetName` function when the user clicks the button. +Now we'll connect the input to our state and wire up the button click handler: -```tsx +```tsx title="components/ContractInteraction.tsx" +"use client"; import { useState } from "react"; import { useScaffoldWriteContract } from "~~/hooks/scaffold-stark/useScaffoldWriteContract"; -export const SetName = () => { - const [newName, setNewName] = useState(""); - +const SetGreeting = () => { + const [greeting, setGreeting] = useState(""); const { sendAsync } = useScaffoldWriteContract({ - calls: [ - { - contractName: "YourContract", - functionName: "setName", - args: [newName], - }, - ], + contractName: "YourContract", + functionName: "set_greeting", + args: [greeting, 0n], // `inputAmount` fixed at 0n }); - const handleSetName = async () => { + const handleSetGreeting = async () => { try { await sendAsync(); } catch (e) { - console.error("Error setting name", e); + console.error("Error setting greeting", e); } }; return ( - <> +
setNewName(e.target.value)} - // highlight-end + onChange={e => setGreeting(e.target.value)} /> - // highlight-start - - // highlight-end - +
); }; + +export default SetGreeting; ``` -### Step 4: Bonus - Adding loading state +### Step 4: Add Loading State -We can use `isPending` returned from `useScaffoldWriteContract` while the transaction is being mined and also disable the button. +Finally, we'll add loading state handling to improve the user experience: -```tsx +```tsx title="components/ContractInteraction.tsx" +"use client"; import { useState } from "react"; import { useScaffoldWriteContract } from "~~/hooks/scaffold-stark/useScaffoldWriteContract"; -export const SetName = () => { - const [newName, setNewName] = useState(""); - // highlight-start +const SetGreeting = () => { + const [greeting, setGreeting] = useState(""); const { sendAsync, isPending } = useScaffoldWriteContract({ - // highlight-end - calls: [ - { - contractName: "YourContract", - functionName: "setName", - args: [newName], - }, - ], + contractName: "YourContract", + functionName: "set_greeting", + args: [greeting, 0n], // `inputAmount` fixed at 0n }); - const handleSetName = async () => { + const handleSetGreeting = async () => { try { await sendAsync(); } catch (e) { - console.error("Error setting name", e); + console.error("Error setting greeting", e); } }; return ( - <> +
setNewName(e.target.value)} + onChange={e => setGreeting(e.target.value)} /> - // highlight-start - - // highlight-end - +
); }; + +export default SetGreeting; ```