Skip to content

Commit

Permalink
Update WaitTxApprovalReceipt recipe to a iterative approach
Browse files Browse the repository at this point in the history
  • Loading branch information
Pabl0cks committed Nov 8, 2023
1 parent 2d86afe commit f2fb2de
Showing 1 changed file with 166 additions and 122 deletions.
288 changes: 166 additions & 122 deletions docs/recipes/WaitTxApprovalReceiptLaunchNextTx.md
Original file line number Diff line number Diff line change
@@ -1,144 +1,127 @@
---
sidebar_position: 3
title: Wait for TxReceipt to Send a Second Tx
description: Learn how to wait for a transaction receipt before sending a second transaction in a multi-step process.
title: Wait for TxReceipt to send next transaction
description: Learn how to wait for TxReceipt before sending a new transaction in a multi-step process.
---

# Wait for Transaction Receipt to Send a Second Transaction

This recipe shows how to create a multi-step transaction process where you wait for the receipt of the first transaction before sending a second transaction.

## Before You Begin
Here is the full code, which we will be implementing in the guide below:

Before you proceed with this recipe, make sure you have the [required dependencies installed](/quick-start/installation), and you're familiar with setting up your [Ethereum development environment](/quick-start/environment).

In this recipe you will use a few hooks:

- [usePublicClient](https://wagmi.sh/react/hooks/usePublicClient) and [useContractWrite](https://wagmi.sh/react/hooks/useContractWrite) from wagmi.
- [useScaffoldContractWrite](/hooks/useScaffoldContractWrite) and [useDeployedContractInfo](/hooks/useDeployedContractInfo) Scaffold ETH-2 hooks.

You'll also use [AddressInput](/components/AddressInput) and [InputBase](/components/InputBase) Scaffold ETH-2 components, [ParseEther viem utility](https://viem.sh/docs/utilities/parseEther.html#parseether) and erc721ABI from wagmi. We recommend checking out the details of these hooks, components and utils before start implementing this recipe.

## Implementation

### Step 1: Create Your Component

Begin by creating a new component, which we'll name "SellNFT.tsx". This component will allow users to perform a multi-step ERC721 approve+listing process for selling a NFT, similar to the ERC20 approve pattern.

Import the necessary libraries and components:

```tsx
```tsx title="components/SellNFT.tsx"
import { useState } from "react";
import type { NextPage } from "next";
import { parseEther } from "viem";
import { erc721ABI, useContractWrite, usePublicClient } from "wagmi";
import { AddressInput, InputBase } from "~~/components/scaffold-eth/Input";
import { useDeployedContractInfo, useScaffoldContractWrite } from "~~/hooks/scaffold-eth";
```

Define the functional component "SellNFT" which will be used to create the user interface for the multi-step transaction process:
import { AddressInput, InputBase } from "~~/components/scaffold-eth/Input";

```tsx
const SellNFT: NextPage = () => {
// Your component code will go here.
};
```
export const SellNFT = () => {
const [address, setAddress] = useState("");
const [tokenId, setTokenId] = useState("");
const [price, setPrice] = useState("");

### Step 2: Initialize Hooks for Contract Interaction
const publicClient = usePublicClient();

Initialize the necessary hooks for interacting with the smart contract. In this example, we'll use two hooks: `useContractWrite` and `useScaffoldContractWrite`.
const { data: NftMarketplace } = useDeployedContractInfo("NftMarketplace");

```tsx
const [address, setAddress] = useState("");
const [tokenId, setTokenId] = useState("");
const [price, setPrice] = useState("");

const publicClient = usePublicClient();

const { data: NftMarketplace } = useDeployedContractInfo("NftMarketplace");

const approveTx = useContractWrite({
address: address,
abi: erc721ABI,
functionName: "approve",
args: [NftMarketplace?.address as string, BigInt(tokenId)],
});

const listNftTx = useScaffoldContractWrite({
contractName: "NftMarketplace",
functionName: "listItem",
args: [address, BigInt(tokenId), parseEther(price)],
});
```
const approveTx = useContractWrite({
address: address,
abi: erc721ABI,
functionName: "approve",
args: [NftMarketplace?.address as string, BigInt(tokenId)],
});

### Step 3: Create the Multi-Step Transaction Process
const listNftTx = useScaffoldContractWrite({
contractName: "NftMarketplace",
functionName: "listItem",
args: [address, BigInt(tokenId), parseEther(price)],
});

Design the user interface to allow users to perform a multi-step transaction process. In this example, we've created a form for selling a NFT:
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const approveHash = await approveTx?.writeAsync();
await publicClient.waitForTransactionReceipt(approveHash);
await listNftTx?.writeAsync();
};

```tsx
return (
<div>
<h2 className="p-8 text-xl font-bold">Sell Your NFT</h2>
<div className="flex w-1/3">
<form className="w-full pl-8" onSubmit={handleSubmit}>
<div className="mb-3">
<label>NFT Address</label>
<AddressInput value={address} onChange={val => setAddress(val)} />
</div>
<div className="mb-3">
<label>NFT Token ID</label>
<InputBase value={tokenId} onChange={val => setTokenId(val)} />
</div>
<div className="mb-3">
<label>Price (ETH)</label>
<InputBase value={price} onChange={val => setPrice(val)} />
</div>
<div className="flex justify-end">
<button className="btn btn-primary" type="submit">
Submit
</button>
</div>
</form>
return (
<div>
<h2 className="p-8 text-xl font-bold">Sell Your NFT</h2>
<div className="flex w-1/3">
<form className="w-full pl-8" onSubmit={handleSubmit}>
<div className="mb-3">
<label>NFT Address</label>
<AddressInput value={address} onChange={val => setAddress(val)} />
</div>
<div className="mb-3">
<label>NFT Token ID</label>
<InputBase value={tokenId} onChange={val => setTokenId(val)} />
</div>
<div className="mb-3">
<label>Price (eth)</label>
<InputBase value={price} onChange={val => setPrice(val)} />
</div>
<div className="flex justify-end">
<button className="btn btn-primary" type="submit">
Submit
</button>
</div>
</form>
</div>
</div>
</div>
);
);
};
```

### Step 4: Implement Multi-Step Transaction Logic
## Implementation

Add logic to handle the multi-step transaction process. In this example, we submit the first transaction to approve the marketplace contract address to transfer our NFT. Then we wait for its receipt before proceeding to list the NFT for sale:
### Step 1: Set Up Your Component

```tsx
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const approveHash = await approveTx?.writeAsync();
await publicClient.waitForTransactionReceipt(approveHash);
await listNftTx?.writeAsync();
Create a new component in the "components" folder. This component will allow users to perform a multi-step `ERC721` approve+listing process for selling a NFT, similar to the `ERC20` approve pattern.

```tsx title="components/SellNFT.tsx"
export const SellNFT = () => {
return (
<div>
<h2 className="p-8 text-xl font-bold">Sell Your NFT</h2>
<div className="flex w-1/3">
<form className="w-full pl-8">
<div className="mb-3">
<label>NFT Address</label>
</div>
<div className="mb-3">
<label>NFT Token ID</label>
</div>
<div className="mb-3">
<label>Price (eth)</label>
</div>
<div className="flex justify-end">
<button className="btn btn-primary">Submit</button>
</div>
</form>
</div>
</div>
);
};
```

### Step 5: Test and Deploy

Test your multi-step transaction process to ensure that it correctly waits for the receipt of the first transaction before proceeding with the second.

## Conclusion

By following these steps, you've created a multi-step transaction process that waits for the receipt of the first transaction before sending the second. This behaviour will be useful for many different types of smart contract interactions, like approving a contract to spend your tokens, or approving a contract to transfer your NFTs.
### Step 2: Initialize Hooks for Contract Interaction

## Full Recipe Code
Initialize the necessary hooks for interacting with the smart contract. In this recipe, we're using:

<details>
<summary>Here's the complete code for the "SellNFT" component:</summary>
- [usePublicClient](https://wagmi.sh/react/hooks/usePublicClient) and [useContractWrite](https://wagmi.sh/react/hooks/useContractWrite) from wagmi.
- [useScaffoldContractWrite](/hooks/useScaffoldContractWrite) and [useDeployedContractInfo](/hooks/useDeployedContractInfo) Scaffold ETH-2 hooks.

```tsx
// highlight-start
import { useState } from "react";
import type { NextPage } from "next";
import { parseEther } from "viem";
import { erc721ABI, useContractWrite, usePublicClient } from "wagmi";
import { AddressInput, InputBase } from "~~/components/scaffold-eth/Input";
import { useDeployedContractInfo, useScaffoldContractWrite } from "~~/hooks/scaffold-eth";

const SellNFT: NextPage = () => {
export const SellNFT = () => {
const [address, setAddress] = useState("");
const [tokenId, setTokenId] = useState("");
const [price, setPrice] = useState("");
Expand All @@ -159,43 +142,104 @@ const SellNFT: NextPage = () => {
functionName: "listItem",
args: [address, BigInt(tokenId), parseEther(price)],
});

const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const approveHash = await approveTx?.writeAsync();
await publicClient.waitForTransactionReceipt(approveHash);
await listNftTx?.writeAsync();
};

// highlight-end
return (
<div>
<h2 className="p-8 text-xl font-bold">Sell Your NFT</h2>
<div className="flex w-1/3">
<form className="w-full pl-8" onSubmit={handleSubmit}>
<form className="w-full pl-8">
<div className="mb-3">
<label>NFT Address</label>
<AddressInput value={address} onChange={val => setAddress(val)} />
</div>
<div className="mb-3">
<label>NFT Token ID</label>
<InputBase value={tokenId} onChange={val => setTokenId(val)} />
</div>
<div className="mb-3">
<label>Price (eth)</label>
<InputBase value={price} onChange={val => setPrice(val)} />
</div>
<div className="flex justify-end">
<button className="btn btn-primary" type="submit">
Submit
</button>
<button className="btn btn-primary">Submit</button>
</div>
</form>
</div>
</div>
);
};

export default SellNFT;
```

</details>
### Step 3: Add all the inputs and submit logic to your form

Create `handleSubmit` logic with the multi-step listing process, waiting for the approval transaction receipt in order to list the NFT. Once you're done with the logic, call it when users submit the form.

Add the inputs to your form, using [AddressInput](/components/AddressInput) and [InputBase](/components/InputBase) Scaffold ETH-2 components.

```tsx
import { useState } from "react";
import { parseEther } from "viem";
import { erc721ABI, useContractWrite, usePublicClient } from "wagmi";
import { useDeployedContractInfo, useScaffoldContractWrite } from "~~/hooks/scaffold-eth";
// highlight-start
import { AddressInput, InputBase } from "~~/components/scaffold-eth/Input";
// highlight-end

export const SellNFT = () => {
const [address, setAddress] = useState("");
const [tokenId, setTokenId] = useState("");
const [price, setPrice] = useState("");

const publicClient = usePublicClient();

const { data: NftMarketplace } = useDeployedContractInfo("NftMarketplace");

const approveTx = useContractWrite({
address: address,
abi: erc721ABI,
functionName: "approve",
args: [NftMarketplace?.address as string, BigInt(tokenId)],
});

const listNftTx = useScaffoldContractWrite({
contractName: "NftMarketplace",
functionName: "listItem",
args: [address, BigInt(tokenId), parseEther(price)],
});

// highlight-start
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const approveHash = await approveTx?.writeAsync();
await publicClient.waitForTransactionReceipt(approveHash);
await listNftTx?.writeAsync();
};
// highlight-end

return (
<div>
<h2 className="p-8 text-xl font-bold">Sell Your NFT</h2>
<div className="flex w-1/3">
<form className="w-full pl-8"
// highlight-start
onSubmit={handleSubmit}>
<div className="mb-3">
<label>NFT Address</label>
<AddressInput value={address} onChange={val => setAddress(val)} />
</div>
<div className="mb-3">
<label>NFT Token ID</label>
<InputBase value={tokenId} onChange={val => setTokenId(val)} />
</div>
<div className="mb-3">
<label>Price (ETH)</label>
<InputBase value={price} onChange={val => setPrice(val)} />
</div>
<div className="flex justify-end">
<button className="btn btn-primary" type="submit">
Submit
</button>
</div>
</form>
</div>
</div>
// highlight-end
);
```

0 comments on commit f2fb2de

Please sign in to comment.