-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
316 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
{ | ||
"monitor-account-balance": "Monitoring account balance" | ||
"monitor-account-balance": "Monitor Account Balance" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
|
||
# Irys Solidity Library | ||
|
||
This will detail how to use the Irys Solidity library to access onchain data. | ||
|
||
It will include an overview and API ref. | ||
|
||
Or if we end up linking perm data to smart contracts in another way, then this will document that. | ||
|
||
Placeholder for now. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
{ | ||
"irys-react": "npx create-react-app", | ||
"vite": "Vite" | ||
"vite": "Vite", | ||
"calling-smart-contracts": "Calling Smart Contracts" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,302 @@ | ||
import { Callout } from "nextra-theme-docs"; | ||
import { Tabs } from 'nextra/components' | ||
|
||
# Calling Smart Contracts with `wagmi` and `viem` | ||
|
||
This guide is for Web2 developers who are comfortable with React and NextJS but are new to working with smart contracts. | ||
|
||
In Web2, calling an API involves sending HTTP requests to a server. In Web3, smart contracts replace the server, and interactions are done via transactions on the blockchain. This guide demonstrates how to call smart contract functions using two popular libraries: wagmi and viem. | ||
|
||
|
||
## wagmi vs viem | ||
|
||
This guide includes code examples for both [`wagmi`](https://wagmi.sh/react/getting-started) and [`viem`](https://viem.sh/). | ||
|
||
- Approach: wagmi is a React Hooks library designed for developers who prefer using hooks. viem, is a TypeScript library focused on low-level blockchain interactions. | ||
|
||
- Abstraction Level: wagmi provides a higher level of abstraction, making it easier to work with common tasks like connecting wallets and reading/writing to contracts using React Hooks. viem offers more granular control. | ||
|
||
- Which to Choose?: Choose wagmi if you're building a dApp with React and want a straightforward way to manage blockchain interactions using hooks. Choose for viem if you need more control over blockchain interactions and prefer a TypeScript-first library. | ||
|
||
## Differences Between Calling APIs and Smart Contracts | ||
|
||
- State Changes: Unlike a Web2 API, smart contract interactions can change the blockchain's state, requiring gas fees and transaction validation. | ||
- Immutability: Once deployed, smart contracts are immutable. | ||
- Transaction Costs: Writing to the blockchain incurs costs, reading from the blockchain is free. | ||
|
||
## Setup | ||
|
||
Install `wagmi` or `viem`. | ||
|
||
<Tabs items={['wagmi', 'viem']}> | ||
<Tabs.Tab> | ||
```bash | ||
npm install wagmi ethers | ||
``` | ||
</Tabs.Tab> | ||
<Tabs.Tab> | ||
```bash | ||
npm install viem ethers | ||
``` | ||
</Tabs.Tab> | ||
</Tabs> | ||
|
||
## Connecting to a Wallet | ||
|
||
Before interacting with a smart contract, you need to connect to a user's wallet. This is similar to authenticating a user in a Web2 app. | ||
|
||
<Tabs items={['wagmi', 'viem']}> | ||
<Tabs.Tab> | ||
```tsx | ||
import { useAccount, useConnect, useDisconnect } from 'wagmi'; | ||
import { InjectedConnector } from 'wagmi/connectors/injected'; | ||
|
||
const WalletConnect = () => { | ||
const { connect } = useConnect({ | ||
connector: new InjectedConnector(), | ||
}); | ||
const { disconnect } = useDisconnect(); | ||
const { isConnected } = useAccount(); | ||
|
||
return ( | ||
<div> | ||
{isConnected ? ( | ||
<button onClick={() => disconnect()}>Disconnect</button> | ||
) : ( | ||
<button onClick={() => connect()}>Connect Wallet</button> | ||
)} | ||
</div> | ||
); | ||
}; | ||
``` | ||
</Tabs.Tab> | ||
<Tabs.Tab> | ||
```tsx | ||
import { createClient, connect } from 'viem'; | ||
import { WalletConnectConnector } from 'viem/connectors/walletConnect'; | ||
|
||
const client = createClient({ | ||
connectors: [ | ||
new WalletConnectConnector({ | ||
options: { | ||
qrcode: true, | ||
}, | ||
}), | ||
], | ||
}); | ||
|
||
const WalletConnect = () => { | ||
const [isConnected, setIsConnected] = React.useState(false); | ||
|
||
const handleConnect = async () => { | ||
const connector = client.getConnector('walletConnect'); | ||
await connect({ connector }); | ||
setIsConnected(true); | ||
}; | ||
|
||
return ( | ||
<div> | ||
{isConnected ? ( | ||
<button onClick={() => setIsConnected(false)}>Disconnect</button> | ||
) : ( | ||
<button onClick={handleConnect}>Connect Wallet</button> | ||
)} | ||
</div> | ||
); | ||
}; | ||
``` | ||
</Tabs.Tab> | ||
</Tabs> | ||
|
||
|
||
## Preparing the Contract | ||
|
||
In Web2, you might interact with a service by initializing an SDK. In Web3, you initialize a contract instance using the ABI and the contract address. | ||
|
||
**ABI (Application Binary Interface)** is a JSON array that describes the interface of the smart contract, including its functions, events, and types. It allows your client code to understand the contract's methods and how to parse the returned data. | ||
|
||
<Tabs items={['wagmi', 'viem']}> | ||
<Tabs.Tab> | ||
```tsx | ||
import { useContract } from 'wagmi'; | ||
import { abi } from './YourContract.json'; // Replace with your contract's ABI | ||
|
||
const contractAddress = '0xYourContractAddress'; // Replace with your contract's address | ||
|
||
const YourContract = () => { | ||
const contract = useContract({ | ||
address: contractAddress, | ||
abi, | ||
}); | ||
|
||
// Now you can call functions on the contract instance | ||
}; | ||
``` | ||
</Tabs.Tab> | ||
<Tabs.Tab> | ||
```tsx | ||
import { createContract } from 'viem'; | ||
|
||
const abi = './YourContract.json'; // Replace with your contract's ABI | ||
|
||
const contractAddress = '0xYourContractAddress'; // Replace with your contract's address | ||
|
||
const contract = createContract({ | ||
address: contractAddress, | ||
abi, | ||
}); | ||
``` | ||
</Tabs.Tab> | ||
</Tabs> | ||
|
||
|
||
## Reading Data from a Smart Contract | ||
|
||
Reading data from a smart contract is similar to making a GET request in Web2. It does not require gas (unless you're interacting with a state-changing view function). | ||
|
||
|
||
<Tabs items={['wagmi', 'viem']}> | ||
<Tabs.Tab> | ||
```tsx | ||
import { useContractRead } from 'wagmi'; | ||
|
||
const YourContract = () => { | ||
const { data, isError, isLoading } = useContractRead({ | ||
address: contractAddress, | ||
abi, | ||
functionName: 'yourReadFunction', // Replace with the function you want to call | ||
}); | ||
|
||
if (isLoading) return <div>Loading...</div>; | ||
if (isError) return <div>Error occurred</div>; | ||
|
||
return <div>Data: {data?.toString()}</div>; | ||
}; | ||
``` | ||
</Tabs.Tab> | ||
<Tabs.Tab> | ||
```tsx | ||
import { readContract } from 'viem'; | ||
|
||
const YourContract = () => { | ||
const fetchData = async () => { | ||
const data = await readContract({ | ||
address: contractAddress, | ||
abi, | ||
functionName: 'yourReadFunction', // Replace with the function you want to call | ||
}); | ||
|
||
return data; | ||
}; | ||
|
||
React.useEffect(() => { | ||
fetchData().then((data) => console.log(data)); | ||
}, []); | ||
|
||
return <div>Check the console for contract data.</div>; | ||
}; | ||
``` | ||
</Tabs.Tab> | ||
</Tabs> | ||
|
||
## Writing Data to a Smart Contract | ||
|
||
<Tabs items={['wagmi', 'viem']}> | ||
<Tabs.Tab> | ||
```tsx | ||
import { useContractWrite, useWaitForTransaction } from 'wagmi'; | ||
|
||
const YourContract = () => { | ||
const { write, data, isError, isLoading } = useContractWrite({ | ||
address: contractAddress, | ||
abi, | ||
functionName: 'yourWriteFunction', // Replace with the function you want to call | ||
}); | ||
|
||
const { isLoading: isTxLoading, isSuccess } = useWaitForTransaction({ | ||
hash: data?.hash, | ||
}); | ||
|
||
if (isTxLoading) return <div>Transaction in progress...</div>; | ||
if (isSuccess) return <div>Transaction successful!</div>; | ||
if (isError) return <div>Error occurred during transaction</div>; | ||
|
||
return <button onClick={() => write()}>Execute Transaction</button>; | ||
}; | ||
``` | ||
</Tabs.Tab> | ||
<Tabs.Tab> | ||
```tsx | ||
import { writeContract, waitForTransactionReceipt } from 'viem'; | ||
|
||
const YourContract = () => { | ||
const handleWrite = async () => { | ||
const transactionHash = await writeContract({ | ||
address: contractAddress, | ||
abi, | ||
functionName: 'yourWriteFunction', // Replace with the function you want to call | ||
}); | ||
|
||
console.log('Transaction Hash:', transactionHash); | ||
}; | ||
|
||
return <button onClick={handleWrite}>Execute Transaction</button>; | ||
}; | ||
``` | ||
</Tabs.Tab> | ||
</Tabs> | ||
|
||
### Waiting for Transaction Receipt | ||
|
||
|
||
Sometimes, you may want to wait for the transaction receipt instead of just monitoring the transaction status. A transaction receipt confirms that the transaction has been included in a block and is finalized. It provides detailed information about the transaction, such as the status, gas used, and any logs emitted during the execution. | ||
|
||
<Tabs items={['wagmi', 'viem']}> | ||
<Tabs.Tab> | ||
```tsx | ||
import { useContractWrite, useWaitForTransactionReceipt } from 'wagmi'; | ||
|
||
const YourContract = () => { | ||
const { write, data, isError, isLoading } = useContractWrite({ | ||
address: contractAddress, | ||
abi, | ||
functionName: 'yourWriteFunction', // Replace with the function you want to call | ||
}); | ||
|
||
const { isLoading: isReceiptLoading, isSuccess, data: receipt } = useWaitForTransactionReceipt({ | ||
hash: data?.hash, | ||
}); | ||
|
||
if (isReceiptLoading) return <div>Waiting for receipt...</div>; | ||
if (isSuccess) return <div>Transaction successful with receipt: {JSON.stringify(receipt)}</div>; | ||
if (isError) return <div>Error occurred during transaction</div>; | ||
|
||
return <button onClick={() => write()}>Execute Transaction</button>; | ||
}; | ||
``` | ||
</Tabs.Tab> | ||
<Tabs.Tab> | ||
```tsx | ||
import { waitForTransactionReceipt } from 'viem'; | ||
|
||
const YourContract = () => { | ||
const handleWrite = async () => { | ||
const transactionHash = await writeContract({ | ||
address: contractAddress, | ||
abi, | ||
functionName: 'yourWriteFunction', // Replace with the function you want to call | ||
}); | ||
|
||
const receipt = await waitForTransactionReceipt({ | ||
hash: transactionHash, | ||
}); | ||
|
||
console.log('Transaction Receipt:', receipt); | ||
}; | ||
|
||
return <button onClick={handleWrite}>Execute Transaction</button>; | ||
}; | ||
``` | ||
</Tabs.Tab> | ||
</Tabs> | ||
|
Empty file.