Skip to content

Commit

Permalink
Merge pull request #191 from tablelandnetwork/dtb/lit-tutorial
Browse files Browse the repository at this point in the history
Lit protocol tutorial & wagmi v2 updates
  • Loading branch information
dtbuchholz authored Mar 20, 2024
2 parents 22c06bb + bbd3605 commit 1027b4a
Show file tree
Hide file tree
Showing 14 changed files with 961 additions and 117 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/algolia.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Algolia # Reindex site search on Algolia

on:
push:
branches:
- main

jobs:
reindex:
runs-on: ubuntu-latest
steps:
- name: Encode Algolia API credentials
run: echo "ALGOLIA_AUTH=$(echo -n ${{ secrets.CRAWLER_USER_ID }}:${{ secrets.CRAWLER_API_KEY }} | base64)" >> $GITHUB_ENV
- name: Reindex Algolia
uses: JamesIves/fetch-api-data-action@v2
with:
endpoint: https://crawler.algolia.com/api/1/crawlers/${{ secrets.CRAWLER_ID }}/reindex
configuration: '{ "method": "POST", "headers": {"Content-Type": "application/json", "Authorization": "Basic ${ALGOLIA_AUTH}" } }'
env:
ALGOLIA_AUTH: ${{ env.ALGOLIA_AUTH }}
1 change: 1 addition & 0 deletions config/sidebars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ const playbooks = [
"playbooks/frameworks/wagmi",
...section("Protocol integrations"),
"playbooks/integrations/ipfs",
"playbooks/integrations/lit",
// ...section("Platforms"),
// "playbooks/platforms/spheron",
];
Expand Down
1 change: 0 additions & 1 deletion docs/contribute/style-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,6 @@ console.log(name.toUpperCase());
// Uncaught TypeError: Cannot read properties of null (reading 'toUpperCase')
```

import { Address } from '@site/src/components/Wallet'
import { SupportedChains, ChainsList, ChainInfo } from '@site/src/components/SupportedChains'

## Components
Expand Down
6 changes: 4 additions & 2 deletions docs/fundamentals/supported-chains.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ keywords:
- blockchains
---

import { ChainsList } from '@site/src/components/SupportedChains'
import { ChainsList, SupportedChains } from '@site/src/components/SupportedChains'

Chain selection makes a significant impact on the database's usability. Choose a chain that’s too slow or expensive, and it won’t be feasible for table writes to occur frequently. Deploy a cross-chain data model for value layering purposes, and certain onchain access control features are lost. This page explains general chain related concepts; the following chains are supported and described in more detail in the subsequent pages.

Expand All @@ -22,7 +22,9 @@ Review the [cost estimation](/fundamentals/architecture/cost-estimator) table th

## Chain information

If would like to dive straight into chain-specific overviews, with decision considerations and other chain information (chain ID, contracts, block explorers, faucets, etc.), head to one of the pages below. The full list of chain-specific details can be found in the [chain info pages](/quickstarts/chains).
If would like to dive straight into chain-specific overviews, with decision considerations and other chain information (chain ID, contracts, block explorers, faucets, etc.), head to one of the pages below. The full list of chain-specific details can be found in the [chain info pages](/quickstarts/chains). The following shows the deployed contracts addresses across all mainnet and testnet chains:

<SupportedChains />

Here's a summary of how the chains works in terms of speed:

Expand Down
1 change: 1 addition & 0 deletions docs/playbooks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ Frameworks show how developers can use Tableland with existing technologies and
As a database with onchain rules, Tableland can easily be used alongside other protocols. There are an endless number of ways protocols can work together, but here are some examples:

- [IPFS & Filecoin](/playbooks/integrations/ipfs): Store files on IPFS, persist them on Filecoin (via web3.storage), and reference the CID in a Tableland table.
- [Lit Protocol](/playbooks/integrations/lit): Encrypt and decrypt table data with secure and decentralized key management.
167 changes: 147 additions & 20 deletions docs/playbooks/frameworks/wagmi.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,26 @@ One great library to use in React apps is [wagmi](https://wagmi.sh/). It offers

## 1. Installation

First, install wagmi, RainbowKit, Tableland, and ethers. If you need help setting up a React project, check out the [React framework quickstart](reactjs).
First, install wagmi, RainbowKit, Tableland, and ethers. If you need help setting up a React project, check out the [React framework quickstart](reactjs). All of these examples will show how to use either wagmi v1 or v2, so you can choose which version you'd like to use.

<Tabs groupId="sdk">
<TabItem value="jsv2" label="wagmi v2" default>

```bash npm2yarn
npm install wagmi@latest @rainbow-me/rainbowkit@latest @tableland/sdk ethers@^5.7.2 @tanstack/react-query
```

</TabItem>
<TabItem value="jsv1" label="wagmi v1">

```bash npm2yarn
npm install --save wagmi @rainbow-me/rainbowkit @tableland/sdk ethers@^5.7.2
npm install wagmi@^1 @rainbow-me/rainbowkit@^1 @tableland/sdk ethers@^5.7.2
```

Note that RainbowKit uses WalletConnect under the hood, which requires you to sign up for an account—[see their docs](https://www.rainbowkit.com/guides/walletconnect-v2) for more details. These examples will use [Alchemy](https://www.alchemy.com/) as the RPC provider, but you can choose whatever provider you'd like.
</TabItem>
</Tabs>

Note that RainbowKit uses WalletConnect under the hood, which requires you to sign up for an account—[see their docs](https://www.rainbowkit.com/guides/walletconnect-v2) for more details.

Now, let's set up our React app with a Vite scaffold:

Expand All @@ -33,14 +46,55 @@ npm create vite@latest starter-app -- --template react

### Wagmi

We'll use a few different files to properly set everything up. Let's start with the first—create a file called `wagmi.js` to handle chain configurations. You should first create a `.env` that handles things like API keys. Our example with use Alchemy for the provider URL and also use WalletConnect's API for the connector. The file should contain:
We'll use a few different files to properly set everything up. Let's start with the first—create a file called `wagmi.js` to handle chain configurations. You should first create a `.env` that handles things like API keys. Our example uses a public provider URL and will also use WalletConnect's API for the connector. The file should contain:

```txt title=".env"
VITE_ALCHEMY_API_KEY=your_key
VITE_WALLET_CONNECT_PROJECT_ID=your_key
ENABLE_TESTNETS=true
```

Note that we'll use `import.meta.env` to access these variables (below) in the `wagmi.js` file. Depending on your frontend setup, it may differ. With Vite, you use `import.meta.env` and prefix the variable with `VITE_`. But, if you're using Next.js, you'd use `process.env` and prefix with `NEXT_PUBLIC_`.

<Tabs groupId="sdk">
<TabItem value="jsv2" label="wagmi v2">

```jsx title="src/wagmi.js"
import "@rainbow-me/rainbowkit/styles.css";
import { getDefaultConfig } from "@rainbow-me/rainbowkit";
import * as chain from "wagmi/chains";
import { http } from "viem";

const chains = [
chain.mainnet,
chain.polygon,
chain.optimism,
chain.arbitrum,
chain.arbitrumNova,
chain.filecoin,
...(import.meta.ENABLE_TESTNETS === "true"
? [
chain.arbitrumSepolia,
chain.sepolia,
chain.polygonMumbai,
chain.optimismSepolia,
chain.filecoinCalibration,
chain.hardhat,
]
: []),
];

const transports = Object.fromEntries(chains.map((c) => [c.id, http()]));

export const config = getDefaultConfig({
appName: "Tableland Starter",
chains,
transports,
projectId: import.meta.env.VITE_WALLET_CONNECT_PROJECT_ID ?? "",
});
```

Note that we'll use `import.meta.env` to access these variables (below) in the `wagmi.js` file. Depending on your frontend setup, it may differ.
</TabItem>
<TabItem value="jsv1" label="wagmi v1" default>

```js title="src/wagmi.js"
import "@rainbow-me/rainbowkit/styles.css";
Expand All @@ -50,30 +104,32 @@ import * as chain from "wagmi/chains";
import { publicProvider } from "wagmi/providers/public";
import { alchemyProvider } from "wagmi/providers/alchemy";

// All of the chains configured below are supported by Tableland
const { chains, publicClient, webSocketPublicClient } = configureChains(
[
chain.mainnet,
chain.polygon,
chain.optimism,
chain.arbitrum,
chain.sepolia,
chain.polygonMumbai,
chain.optimismSepolia,
chain.arbitrumSepolia,
chain.filecoinCalibration,
chain.hardhat,
chain.arbitrumNova,
chain.filecoin,
...(import.meta.ENABLE_TESTNETS === "true"
? [
chain.arbitrumSepolia,
chain.sepolia,
chain.polygonMumbai,
chain.optimismSepolia,
chain.filecoinCalibration,
chain.hardhat,
]
: []),
],
[
alchemyProvider({ apiKey: VITE_ALCHEMY_API_KEY ?? "" }), // Set up an Alchemy account: https://www.alchemy.com/
publicProvider(),
]
[publicProvider()]
);

const { connectors } = getDefaultWallets({
appName: "Tableland Starter",
chains,
projectId: process.env.WALLET_CONNECT_PROJECT_ID ?? "", // Set up a WalletConnect account: https://walletconnect.com/
projectId: import.meta.env.VITE_WALLET_CONNECT_PROJECT_ID ?? "",
});

export const config = createConfig({
Expand All @@ -86,10 +142,43 @@ export const config = createConfig({
export { chains };
```

</TabItem>
</Tabs>

### Providers

Next, we'll set up providers that wrap our React component with the wagmi config. Create a file called `providers.jsx` and add the following:

<Tabs groupId="sdk">
<TabItem value="jsv2" label="wagmi v2">

```jsx title="src/providers.jsx"
import { RainbowKitProvider, darkTheme } from "@rainbow-me/rainbowkit";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import * as React from "react";
import { WagmiProvider } from "wagmi";
import { config } from "./wagmi";

const queryClient = new QueryClient();

export function Providers({ children }) {
const [mounted, setMounted] = React.useState(false);
React.useEffect(() => setMounted(true), []);
return (
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<RainbowKitProvider theme={darkTheme()}>
{mounted && children}
</RainbowKitProvider>
</QueryClientProvider>
</WagmiProvider>
);
}
```

</TabItem>
<TabItem value="jsv1" label="wagmi v1" default>

```js title="src/providers.jsx"
import { RainbowKitProvider, darkTheme } from "@rainbow-me/rainbowkit";
import * as React from "react";
Expand All @@ -109,6 +198,9 @@ export function Providers({ children }) {
}
```

</TabItem>
</Tabs>

### App component

In your `main.jsx` component, replace it with the following:
Expand All @@ -133,7 +225,39 @@ ReactDOM.createRoot(document.getElementById("root")).render(

Since wagmi is not natively compatible with ethers, we'll need to create a hook that adapts the wagmi account (viem) to an ethers account. Create a directory called `hooks` and a file called `useSigner.js`. Then, add the following:

```js title="src/hooks/useEthersAccount.js"
<Tabs groupId="sdk">
<TabItem value="jsv2" label="wagmi v2">

```js title="src/hooks/useSigner.js"
import { useMemo } from "react";
import { providers } from "ethers";
import { useWalletClient } from "wagmi";

function walletClientToSigner(walletClient) {
const { account, chain, transport } = walletClient;
const network = {
chainId: chain.id,
name: chain.name,
ensAddress: chain.contracts?.ensRegistry?.address,
};
const provider = new providers.JsonRpcProvider(transport.url, network);
const signer = provider.getSigner(account.address);
return signer;
}

export function useSigner({ chainId } = {}) {
const { data: walletClient } = useWalletClient({ chainId });
return useMemo(
() => (walletClient ? walletClientToSigner(walletClient) : undefined),
[walletClient]
);
}
```
</TabItem>
<TabItem value="jsv1" label="wagmi v1" default>
```js title="src/hooks/useSigner.js"
// Convert wagmi/viem `WalletClient` to ethers `Signer`
import { useMemo } from "react";
import { useWalletClient } from "wagmi";
Expand All @@ -160,6 +284,9 @@ export function useSigner({ chainId } = {}) {
}
```
</TabItem>
</Tabs>
## 3. Tableland setup
Now that we have everything ready, we can use the `useSigner` hook we just created in our Tableland setup. Create a file called `Tableland.jsx` and add the following. We'll keep this example simple and just show how to create a table, which uses the `useSigner` hook that's stored as the `signer` variable in the app's state.
Expand Down Expand Up @@ -226,7 +353,7 @@ function App() {
export default App;
```
This boilerplate will display a connect wallet button in the navbar. Once a user makes the connection, the signer will now be available in the Tableland logic from step 3!
This boilerplate will display a connect wallet button in the navbar. Once a user makes the connection, the signer will now be available in the Tableland logic!
:::tip
For more examples, you can [check out the templates](/quickstarts/templates) we've created, which also include a TypeScript example of what we walked through as well as Next.js examples.
Expand Down
Loading

0 comments on commit 1027b4a

Please sign in to comment.