Skip to content

Commit

Permalink
add: tx helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
clmntsnr committed Dec 20, 2024
1 parent 3c7c7f5 commit 9aad5c5
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 25 deletions.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"moment": "^2.30.1",
"numerable": "^0.3.15",
"qs": "^6.13.0",
"react": "^18.2.0",
"react": "^18.3.1",
"react-dom": "^18.2.0",
"react-responsive": "^10.0.0",
"recharts": "^2.12.7",
Expand All @@ -61,9 +61,9 @@
"tailwindcss": "^3.4.12",
"tailwindcss-animate": "^1.0.7",
"typedoc": "^0.26.7",
"viem": "2.x",
"vite-plugin-dts": "^4.2.1",
"wagmi": "^2.12.10",
"viem": "2.21.54",
"wagmi": "^2.14.1",
"zustand": "^5.0.0-rc.2"
},
"devDependencies": {
Expand Down
25 changes: 17 additions & 8 deletions src/components/dapp/TransactionButton.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type ReactNode, useCallback } from "react";
import { type ResolvedRegister, type UseSendTransactionReturnType, useSendTransaction } from "wagmi";
import { useWalletContext } from "../../context/Wallet.context";
import Button, { type ButtonProps } from "../primitives/Button";
import Icon from "../primitives/Icon";

Expand All @@ -11,18 +12,26 @@ export type TransactionButtonProps = ButtonProps & {

export default function TransactionButton({ tx, name, children, onExecute, ...props }: TransactionButtonProps) {
const sendTxHook = useSendTransaction();
const { sendTransactionAsync, status } = sendTxHook;
const { status } = sendTxHook;
const { address: user, client, sendTransaction } = useWalletContext();

const execute = useCallback(async () => {
if (!tx) return;
console.log("CLIENT", client);

const hash = await sendTransactionAsync({
to: tx.to as `0x${string}`,
data: tx.data as `0x${string}`,
});
if (!tx || !user || !client) return;

onExecute?.(hash);
}, [tx, sendTransactionAsync, onExecute]);
const hash = await sendTransaction?.([
{
chain: client.chain,
account: user,
to: tx.to,
data: tx.data,
value: tx.value,
},
]);

hash && onExecute?.(hash);
}, [tx, client, user, sendTransaction, onExecute]);

return (
<Button {...props} onClick={execute}>
Expand Down
5 changes: 4 additions & 1 deletion src/context/Dapp.context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { WalletProvider } from "./Wallet.context";

//TODO: remove merkl-related typings in favor of redeclarations for better abstraction
import type { Chain, Explorer } from "@merkl/api";
import type { WalletOptions } from "../hooks/useWalletState";
import type { SizingConfig } from "../utils/tailwind";

export type DAppContextType = { flag?: string };
Expand All @@ -26,6 +27,7 @@ export type DAppProviderProps = {
sizing: SizingConfig;
modes: Mode[];
chains: (Chain & { explorers: Explorer[] })[];
walletOptions?: WalletOptions;
};

export function DAppProvider({
Expand All @@ -35,10 +37,11 @@ export function DAppProvider({
modes,
children,
chains,
walletOptions,
}: PropsWithChildren<DAppProviderProps>) {
return (
<ThemeProvider sizing={sizing} themes={themes ?? demoThemes} modes={modes}>
<WalletProvider chains={chains.filter(({ id }) => id !== 1337)} config={config}>
<WalletProvider walletOptions={walletOptions} chains={chains.filter(({ id }) => id !== 1337)} config={config}>
{children}
</WalletProvider>
</ThemeProvider>
Expand Down
19 changes: 11 additions & 8 deletions src/context/Wallet.context.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
//TODO: remove merkl-related typings in favor of redeclarations for better abstraction
import type { Chain, Explorer } from "@merkl/api";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { type PropsWithChildren, createContext, useContext } from "react";
import { type ResolvedRegister, WagmiProvider } from "wagmi";
import useWalletState from "../hooks/useWalletState";

//TODO: remove merkl-related typings in favor of redeclarations for better abstraction
import type { Chain, Explorer } from "@merkl/api";
import useWalletState, { type WalletOptions } from "../hooks/useWalletState";

export type WalletContextType = ReturnType<typeof useWalletState>;

Expand All @@ -22,22 +21,26 @@ export function useWalletContext() {
export type WalletProviderProps = {
config: ResolvedRegister["config"];
chains: (Chain & { explorers: Explorer[] })[];
walletOptions?: WalletOptions;
};

function WalletStateProvider({
children,
chains,
}: PropsWithChildren & { chains: (Chain & { explorers: Explorer[] })[] }) {
const walletState = useWalletState(chains);
options,
}: PropsWithChildren & { chains: (Chain & { explorers: Explorer[] })[]; options?: WalletOptions }) {
const walletState = useWalletState(chains, options);

return <WalletContext.Provider value={walletState}>{children}</WalletContext.Provider>;
}

export function WalletProvider({ config, children, chains }: PropsWithChildren<WalletProviderProps>) {
export function WalletProvider({ config, children, chains, walletOptions }: PropsWithChildren<WalletProviderProps>) {
return (
<QueryClientProvider client={queryClient}>
<WagmiProvider config={config}>
<WalletStateProvider chains={chains}>{children}</WalletStateProvider>
<WalletStateProvider options={walletOptions} chains={chains}>
{children}
</WalletStateProvider>
</WagmiProvider>
</QueryClientProvider>
);
Expand Down
45 changes: 40 additions & 5 deletions src/hooks/useWalletState.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,50 @@
import { switchChain as wagmiCoreSwitchChain } from "@wagmi/core";
import { useState } from "react";
import { useAccount, useConfig, useConnect, useDisconnect } from "wagmi";
import { getWalletClient, switchChain as wagmiCoreSwitchChain } from "@wagmi/core";
import { useCallback, useEffect, useState } from "react";
import { type Config, useAccount, useConfig, useConnect, useDisconnect } from "wagmi";

//TODO: remove merkl-related typings in favor of redeclarations for better abstraction
import type { Chain, Explorer } from "@merkl/api";
import type { WalletClient } from "viem";

export default function useWalletState(chains: (Chain & { explorers: Explorer[] })[]) {
const config = useConfig();
export type WalletOptions = {
client?: (c: WalletClient) => Promise<WalletClient>;
transaction?: (
tx: Parameters<WalletClient["sendTransaction"]>,
context: { client: WalletClient; config: Config },
) => ReturnType<WalletClient["sendTransaction"]>;
};

export default function useWalletState(chains: (Chain & { explorers: Explorer[] })[], options?: WalletOptions) {
const config = useConfig<Config>();
const wagmiConnect = useConnect();
const wagmiDisconnect = useDisconnect();
const account = useAccount();

const [blockNumber] = useState<number>();
const [client, setClient] = useState<WalletClient>();

const wrapClient = useCallback(async () => {
const _client = await getWalletClient<typeof config, 1>(config);

return (await options?.client?.(_client)) ?? _client;
}, [config, options?.client]);

// biome-ignore lint/correctness/useExhaustiveDependencies: required for correctness
useEffect(() => {
async function set() {
setClient(await wrapClient());
}

set();
}, [account, wrapClient]);

const wrapTransaction = useCallback(
async (tx: Parameters<WalletClient["sendTransaction"]>) => {
if (!client) return;
return (await options?.transaction?.(tx, { client, config })) ?? client.sendTransaction(...tx);
},
[client, options?.transaction, config],
);

async function connect(connectorId: string) {
const connector = config.connectors.find(({ id }) => id === connectorId);
Expand All @@ -32,9 +65,11 @@ export default function useWalletState(chains: (Chain & { explorers: Explorer[]
return {
config,
chains,
client,
chainId: account.chainId,
switchChain,
blockNumber,
sendTransaction: wrapTransaction,
address: account.address,
connected: account.isConnected,
connector: account.connector,
Expand Down

0 comments on commit 9aad5c5

Please sign in to comment.