Skip to content

Commit

Permalink
Implemented and documented useReadContract hook
Browse files Browse the repository at this point in the history
  • Loading branch information
vla-dev committed Nov 14, 2024
1 parent 1a39015 commit 446ce06
Show file tree
Hide file tree
Showing 11 changed files with 249 additions and 101 deletions.
2 changes: 1 addition & 1 deletion demo/src/Authentication.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const Authentication = () => {
if (e instanceof UserRefusedToSignAuthError) {
setSignature("User refused to sign");
} else {
setSignature(e);
setSignature(JSON.stringify(e));
}
}
};
Expand Down
170 changes: 99 additions & 71 deletions demo/src/ContractsBenchmark.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,135 +2,163 @@ import {
useWriteContract,
useWallet,
useWatchTransactionReceipt,
} from "@buidlerlabs/hashgraph-react-wallets";
import { counterABI } from "./ABIs/Counter";
import { ContractId } from "@hashgraph/sdk";
import toast from "react-hot-toast";
import { PulseLoader } from "react-spinners";
import { useState } from "react";
import WhitelistAddress from "./WhitelistAddress";
useReadContract,
} from '@buidlerlabs/hashgraph-react-wallets'
import { counterABI } from './ABIs/Counter'
import { ContractId } from '@hashgraph/sdk'
import toast from 'react-hot-toast'
import { PulseLoader } from 'react-spinners'
import { useState } from 'react'
import WhitelistAddress from './WhitelistAddress'

const COUNTER_CONTRACT_ID = ContractId.fromString("0.0.3532256");
const COUNTER_CONTRACT_ID = ContractId.fromString('0.0.3532256')

const ContractsBenchmark = () => {
const { isConnected } = useWallet();
const { watch } = useWatchTransactionReceipt();
const [loading, setLoading] = useState(false);
const { isConnected } = useWallet()
const { watch } = useWatchTransactionReceipt()
const [loading, setLoading] = useState(false)

const { writeContract } = useWriteContract();
const { writeContract } = useWriteContract()
const { readContract } = useReadContract()

const onSubmitted = (hashOrTransactionId) => {
watch(hashOrTransactionId, {
onSuccess: (transaction) => {
console.log(transaction);
console.log(transaction)

const label = (
<div>
<div>SUCCESS: </div>
<a
href={`https://hashscan.io/testnet/transaction/${transaction.consensus_timestamp}`}
target="_blank"
>
<a href={`https://hashscan.io/testnet/transaction/${transaction.consensus_timestamp}`} target='_blank'>
https://hashscan.io/testnet/transaction/
{transaction.consensus_timestamp}
</a>
</div>
);
)

toast.success(label, {
icon: "✅",
style: { maxWidth: "unset" },
icon: '✅',
style: { maxWidth: 'unset' },
duration: 6000,
});
})

setLoading(false);
return transaction;
setLoading(false)
return transaction
},
onError: (transaction, error) => {
console.log(error);
console.log(error)
const label = (
<div>
<div>FAILED: {transaction.result}</div>
<a
href={`https://hashscan.io/testnet/transaction/${transaction.consensus_timestamp}`}
target="_blank"
>
<a href={`https://hashscan.io/testnet/transaction/${transaction.consensus_timestamp}`} target='_blank'>
https://hashscan.io/testnet/transaction/
{transaction.consensus_timestamp}
</a>
</div>
);
)

toast.error(label, {
icon: "❌",
style: { maxWidth: "unset" },
icon: '❌',
style: { maxWidth: 'unset' },
duration: 6000,
});
})

setLoading(false);
return transaction;
setLoading(false)
return transaction
},
});
};
})
}

const handleWriteContract = async (functionName) => {
try {
setLoading(true);
setLoading(true)

const transactionReceiptOrHash = await writeContract({
contractId: COUNTER_CONTRACT_ID,
abi: counterABI,
functionName,
metaArgs: { gas: 120_000 },
});

console.log({ transactionReceiptOrHash });
if (
transactionReceiptOrHash &&
typeof transactionReceiptOrHash === "string"
) {
onSubmitted(transactionReceiptOrHash);
})

console.log({ transactionReceiptOrHash })
if (transactionReceiptOrHash && typeof transactionReceiptOrHash === 'string') {
onSubmitted(transactionReceiptOrHash)
}
} catch (e) {
console.log(JSON.parse(JSON.stringify(e)));
console.error(e);
setLoading(false);
console.log(JSON.parse(JSON.stringify(e)))
console.error(e)
setLoading(false)
}
};
}

const handleReadContract = async () => {
try {
setLoading(true)

const count = await readContract({
address: `0x${COUNTER_CONTRACT_ID.toSolidityAddress()}`,
abi: counterABI,
functionName: 'get',
})

const label = (
<div>
<div>SUCCESS: </div>
<div>Count: {Number(count)}</div>
</div>
)

toast.success(label, {
icon: '✅',
style: { maxWidth: 'unset' },
duration: 6000,
})
} catch (e) {
console.error(e)
} finally {
setLoading(false)
}
}

return (
<div>
<div>Contracts:</div>
<div style={{ display: 'flex', gap: '1rem' }}>
<div>Contracts:</div>
{loading && <PulseLoader size={10} />}
</div>
<br />
<div>Write contract</div>
<div style={{ display: "flex", gap: "1rem" }}>
<div style={{ display: "flex", gap: "0.2rem" }}>
<button
onClick={() => handleWriteContract("inc")}
disabled={!isConnected}
>

<div style={{ display: 'flex', flexDirection: 'column' }}>
<div>Write contract</div>

<div style={{ display: 'flex', gap: '0.2rem' }}>
<button onClick={() => handleWriteContract('inc')} disabled={!isConnected}>
Increment
</button>
<button
onClick={() => handleWriteContract("dec")}
disabled={!isConnected}
>
<button onClick={() => handleWriteContract('dec')} disabled={!isConnected}>
Decrement
</button>
<button
onClick={() => handleWriteContract("testError")}
disabled={!isConnected}
>
<button onClick={() => handleWriteContract('testError')} disabled={!isConnected}>
Test error
</button>
</div>
</div>

{loading && <PulseLoader size={10} />}
<br />

<div style={{ display: 'flex', flexDirection: 'column' }}>
<div>Read contract</div>

<div style={{ display: 'flex', gap: '0.2rem' }}>
<button onClick={handleReadContract} disabled={!isConnected}>
Get count
</button>
</div>
</div>
<hr/>
<WhitelistAddress/>
<hr />
<WhitelistAddress />
</div>
);
};
)
}

export default ContractsBenchmark;
export default ContractsBenchmark
1 change: 1 addition & 0 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export default defineConfig({
{ text: 'useTokensBalance', link: '/hooks/use-tokens-balance' },
{ text: 'useWatchTransactionReceipt', link: '/hooks/use-watch-transaction-receipt' },
{ text: 'useWriteContract', link: '/hooks/use-write-contract' },
{ text: 'useReadContract', link: '/hooks/use-read-contract' },
],
},
],
Expand Down
1 change: 1 addition & 0 deletions docs/hooks/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ Various hooks have been coded and made available for usage:
- [`useTokensBalance()`](/hooks/use-tokens-balance)
- [`useWatchTransactionReceipt()`](/hooks/use-watch-transaction-receipt)
- [`useWriteContract()`](/hooks/use-write-contract)
- [`useReadContract()`](/hooks/use-read-contract)
- [`useWallet()`](/hooks/use-wallet)
81 changes: 81 additions & 0 deletions docs/hooks/use-read-contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
outline: deep
---

# useReadContract()

Use it to read a smart contract state via JSON-RPC.

::: info
The built-in chain configurations default to using the [hashio.io](https://hashio.io) JSON-RPC relay.
:::

## Usage

```tsx
import { ContractId } from "@hashgraph/sdk";
import { useReadContract } from '@buidlerlabs/hashgraph-react-wallets'
import { counterABI } from './ABIs'

const CONTRACT_ID = ContractId.fromString("0.0.123456");

const App = () => {
const { readContract } = useReadContract();

const handleGetCount = async () => {
try {
const count = await readContract({
address: `0x${CONTRACT_ID.toSolidityAddress()}`,
abi: counterABI,
functionName: 'get',
})

console.log(Number(count))
} catch (e) {
console.error(e)
}
}

return <button onClick={handleGetCount}>Get count</button>
```
## Parameters
```ts
interface IUseWriteContractProps<Connector> {
connector?: Connector | null
chain?: Chain
}
```
::: warning
By default, this implementation uses the chain configuration of the currently connected wallet. To use it without a connected wallet, specify the `chain` parameter in the configuration.
:::
#### - connector
- Type: `HWBridgeConnector`
- Required: `false`
#### - chain
- Type: `Chain`
- Required: `false`
## `readContract()`
Read more about its usage on [viem.sh](https://viem.sh/docs/contract/readContract#parameters)
## Return Type
```ts
// import { createPublicClient } from 'viem'

type TResult = {
readContract: async <
readParameters extends Parameters<ReturnType<typeof createPublicClient>['readContract']>[0],
>(
parameters: readParameters,
): Promise<TData>
}
```
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@buidlerlabs/hashgraph-react-wallets",
"version": "2.2.0",
"version": "2.3.0",
"description": "A lightweight library that aims to provide an easier way to interact with the hedera network from a UI perspective",
"keywords": [
"react",
Expand Down
27 changes: 27 additions & 0 deletions src/actions/contracts.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ import { HWBridgeSession } from '../hWBridge'
import { writeContract as wagmi_writeContract } from 'wagmi/actions'
import {
Abi,
Chain,
Client,
ContractFunctionArgs,
ContractFunctionName,
createPublicClient,
encodeFunctionData,
fromHex,
http,
getContract as viem_getContract,
} from 'viem'
import { ConnectorType } from '../constants'
Expand Down Expand Up @@ -38,6 +41,30 @@ export const getContract = async <TWallet extends HWBridgeSession>({
})
}

export const readContract = async <
TWallet extends HWBridgeSession,
readParameters extends Parameters<ReturnType<typeof createPublicClient>['readContract']>[0],
>({
wallet,
parameters,
chain,
}: {
wallet: TWallet
parameters: readParameters
chain?: Chain
}) => {
const _chain = chain ?? wallet.connector?.chain ?? null

if (!_chain) return null;

const publicClient = createPublicClient({
chain: _chain,
transport: http(),
})

return await publicClient.readContract(parameters)
}

export const writeContract = async <
TWallet extends HWBridgeSession,
const abi extends Abi | readonly unknown[],
Expand Down
Loading

0 comments on commit 446ce06

Please sign in to comment.