Skip to content

Commit

Permalink
fix
Browse files Browse the repository at this point in the history
  • Loading branch information
tash-2s committed Feb 16, 2024
1 parent 4f61756 commit ad34bd5
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 102 deletions.
155 changes: 78 additions & 77 deletions examples/minimal/packages/client-react-external-wallet/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,23 @@
import { useState, useEffect } from "react";
import { BaseError } from "viem";
import {
usePublicClient,
useWalletClient,
useAccount,
useConnect,
useDisconnect,
useWalletClient,
type WalletClient,
type PublicClient,
useNetwork,
useSwitchNetwork,
} from "wagmi";
import { syncToZustand } from "@latticexyz/store-sync/zustand";
import { type ContractWrite, getContract } from "@latticexyz/common";
import { Subject, share } from "rxjs";
import { share } from "rxjs";
import { useNetworkConfig, useWorldContract } from "./mud/networkConfig";
import { syncStore, StoreProvider, useStore, type Store } from "./mud/store";
import mudConfig from "contracts/mud.config";
import { BaseError, type Hex } from "viem";
import IWorldAbi from "contracts/out/IWorld.sol/IWorld.abi.json";
import { useNetworkConfig, type NetworkConfig } from "./mud/networkConfig";

type Store = Awaited<ReturnType<typeof syncStore>>;

const syncStore = async (networkConfig: NetworkConfig, publicClient: PublicClient) => {
const { tables, useStore, latestBlock$, storedBlockLogs$, waitForTransaction } = await syncToZustand({
config: mudConfig,
address: networkConfig.worldAddress,
publicClient,
startBlock: BigInt(networkConfig.initialBlockNumber),
});

return { tables, useStore, latestBlock$, storedBlockLogs$, waitForTransaction };
};

export const App = () => {
const networkConfig = useNetworkConfig();
const publicClient = usePublicClient();
const { isConnected } = useAccount();

const [store, setStore] = useState<Store | null>(null);

Expand All @@ -42,83 +28,66 @@ export const App = () => {
return (
<>
<Connect />
{store ? <Synced store={store} /> : <></>}
{isConnected && <Wallet />}
{store && (
<StoreProvider store={store}>
<Synced />
</StoreProvider>
)}
</>
);
};

const getWorldContract = (address: Hex, publicClient: PublicClient, walletClient: WalletClient) => {
const write$ = new Subject<ContractWrite>();
const worldContract = getContract({
address,
abi: IWorldAbi,
publicClient,
walletClient,
onWrite: (write) => write$.next(write),
});

return { worldContract, write$ };
};
export const Synced = () => {
const store = useStore();
const { chain } = useNetwork();
const networkConfig = useNetworkConfig();
const { data: walletClient } = useWalletClient();

export const Synced = (props: { store: Store }) => {
const { isConnected } = useAccount();
// const networkConfig = useNetworkConfig();
// const publicClient = usePublicClient();
// const { data: walletClient } = useWalletClient();

// const { worldContract, write$ } = _getContract(networkConfig.worldAddress as Hex, publicClient, walletClient!);

// useEffect(() => {
// if (import.meta.env.DEV) {
// import("@latticexyz/dev-tools").then(({ mount }) =>
// mount({
// config: mudConfig,
// publicClient: publicClient,
// walletClient: walletClient!,
// latestBlock$: props.store.latestBlock$,
// storedBlockLogs$: props.store.storedBlockLogs$,
// worldAddress: worldContract.address,
// worldAbi: worldContract.abi,
// write$: write$.asObservable().pipe(share()),
// useStore: props.store.useStore,
// })
// );
// }
// }, [isConnected]);

const counter = props.store.useStore((state) => state.getValue(props.store.tables.CounterTable, {}));
const counter = store.useStore((state) => state.getValue(store.tables.CounterTable, {}));

return (
<>
<div>Counter: {counter?.value ?? "unset"}</div>
<div>{isConnected ? <Incrementer /> : <></>}</div>
<div>{walletClient && chain && chain!.id === networkConfig.chainId && <Connected />}</div>
</>
);
};

const useWorldContract = () => {
const networkConfig = useNetworkConfig();
const publicClient = usePublicClient();
const { data: walletClient } = useWalletClient();

const worldContract = getWorldContract(networkConfig.worldAddress, publicClient, walletClient!);

return { worldContract, networkConfig, publicClient };
};

const Incrementer = () => {
const Connected = () => {
const store = useStore();
const {
worldContract: { worldContract },
worldContract: { worldContract, write$ },
publicClient,
walletClient,
} = useWorldContract();

useEffect(() => {
if (import.meta.env.DEV) {
import("@latticexyz/dev-tools").then(({ mount }) =>
mount({
config: mudConfig,
publicClient: publicClient,
walletClient: walletClient,
latestBlock$: store.latestBlock$,
storedBlockLogs$: store.storedBlockLogs$,
worldAddress: worldContract.address,
worldAbi: worldContract.abi,
write$: write$.asObservable().pipe(share()),
useStore: store.useStore,
})
);
}
}, [walletClient.account.address]);

return (
<button type="button" onClick={() => worldContract.write.increment()}>
Increment
</button>
);
};

// TODO: Link
// Based on https://github.com/wevm/create-wagmi/blob/create-wagmi%401.0.5/templates/vite-react/default/src/App.tsx#L28
export function Connect() {
const { connector, isConnected } = useAccount();
const { connect, connectors, error, isLoading, pendingConnector } = useConnect();
Expand All @@ -133,7 +102,7 @@ export function Connect() {
.filter((x) => x.ready && x.id !== connector?.id)
.map((x) => (
<button key={x.id} onClick={() => connect({ connector: x })}>
{x.name}
Connect {x.name}
{isLoading && x.id === pendingConnector?.id && " (connecting)"}
</button>
))}
Expand All @@ -143,3 +112,35 @@ export function Connect() {
</div>
);
}

export function Wallet() {
const { chain } = useNetwork();
const { chains, error, isLoading, pendingChainId, switchNetwork } = useSwitchNetwork();
const { address } = useAccount();

const otherChains = chains.filter((x) => x.id !== chain?.id);

return (
<div>
<div>{address}</div>
<div>
Connected to {chain?.name ?? chain?.id}
{chain?.unsupported && " (unsupported)"}
</div>
<br />
{switchNetwork && otherChains.length && (
<div>
Switch to:{" "}
{otherChains.map((x) => (
<button key={x.id} onClick={() => switchNetwork(x.id)}>
{x.name}
{isLoading && x.id === pendingChainId && " (switching)"}
</button>
))}
</div>
)}

<div>{error?.message}</div>
</div>
);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createPublicClient, fallback, webSocket, http, type ClientConfig } from "viem";
import { configureChains, createConfig } from "wagmi";
import { publicProvider } from "wagmi/providers/public";
import { InjectedConnector } from "wagmi/connectors/injected";
import { transportObserver } from "@latticexyz/common";
import { type MUDChain } from "@latticexyz/common/chains";
Expand All @@ -13,7 +14,7 @@ export function getWagmiConfig(chain: MUDChain) {

const publicClient = createPublicClient(clientOptions);

const { chains } = configureChains([chain], []);
const { chains } = configureChains([chain], [publicProvider()]);

const wagmiConfig = createConfig({
autoConnect: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { createContext, type ReactNode, useContext } from "react";
import { type Hex } from "viem";
import worlds from "contracts/worlds.json";
import { usePublicClient, useWalletClient, type WalletClient, type PublicClient } from "wagmi";
import { Subject } from "rxjs";
import { type ContractWrite, getContract } from "@latticexyz/common";
import { supportedChains } from "./supportedChains";
import worlds from "contracts/worlds.json";
import IWorldAbi from "contracts/out/IWorld.sol/IWorld.abi.json";

export type NetworkConfig = ReturnType<typeof getNetworkConfig>;

Expand Down Expand Up @@ -50,3 +54,30 @@ export const useNetworkConfig = () => {
if (!value) throw new Error("Must be used within a NetworkConfigProvider");
return value;
};

const getWorldContract = (address: Hex, publicClient: PublicClient, walletClient: WalletClient) => {
const write$ = new Subject<ContractWrite>();
const worldContract = getContract({
address,
abi: IWorldAbi,
publicClient,
walletClient,
onWrite: (write) => write$.next(write),
});

return { worldContract, write$ };
};

export const useWorldContract = () => {
const networkConfig = useNetworkConfig();
const publicClient = usePublicClient();
const { data: walletClient } = useWalletClient();

if (!walletClient) {
throw new Error("useWorldContract is used incorrectly");
}

const worldContract = getWorldContract(networkConfig.worldAddress, publicClient, walletClient);

return { worldContract, networkConfig, publicClient, walletClient };
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { createContext, type ReactNode, useContext } from "react";
import { type PublicClient } from "wagmi";
import { syncToZustand } from "@latticexyz/store-sync/zustand";
import { type NetworkConfig } from "./networkConfig";
import mudConfig from "contracts/mud.config";

export type Store = Awaited<ReturnType<typeof syncStore>>;

export const syncStore = async (networkConfig: NetworkConfig, publicClient: PublicClient) => {
const { tables, useStore, latestBlock$, storedBlockLogs$, waitForTransaction } = await syncToZustand({
config: mudConfig,
address: networkConfig.worldAddress,
publicClient,
startBlock: BigInt(networkConfig.initialBlockNumber),
});

return { tables, useStore, latestBlock$, storedBlockLogs$, waitForTransaction };
};

const StoreContext = createContext<Store | null>(null);

type Props = {
children: ReactNode;
store: Store;
};

export const StoreProvider = ({ children, store }: Props) => {
const currentValue = useContext(StoreContext);
if (currentValue) throw new Error("StoreProvider can only be used once");
return <StoreContext.Provider value={store}>{children}</StoreContext.Provider>;
};

export const useStore = () => {
const value = useContext(StoreContext);
if (!value) throw new Error("Must be used within a StoreProvider");
return value;
};

0 comments on commit ad34bd5

Please sign in to comment.