Get Started: Wagmi Apps
Estimated time to read: 6 minutes
Enable unified-balance and chain abstracted transactions in Web3 apps built with the Wagmi library by integrating with the Arcana CA Wagmi SDK.
Arcana CA Wagmi SDK lets you add chain abstracted bridge
and transfer
functions in wagmi
apps. Replace the useSendTransaction
and useWriteContract
hooks of the Wagmi library with those provided by the SDK to enable chain abstraction in a transparent manner.
Wagmi Plug & Play Widget
The Arcana CA Wagmi SDK supports a plug-and-play UI modal that displays the unified balance within the Wagmi app context. Authenticated app users can view the unified balance via the plug-and-play widget and issue blockchain transactions through any browser-based third-party wallets connected to the Wagmi app.
1. Install
npm install --save @arcana/ca-wagmi
yarn add @arcana/ca-wagmi
2. Integrate
Use the CAProvider
component from Arcana CA Wagmi SDK in the app code. Make sure you import the following functions from the ca-wagmi and not from the wagmi SDK.
useBalance
- Unify the specified token balance across chains - USDC, USDT, ETHuseSendTransaction
- Chain abstracted Send TransactionuseWriteContract
- Chain abstracted Write ContractuseUnifiedBalance
- Get unified balance for all tokens across all chains
The SDK also offers additional hooks:
useBalanceModal
- Display a plug and play widget containing the unified balanceuseCAFn
- Allows chain abstracted bridge and transfer functions
For details, see Arcana CA Wagmi SDK Reference.
Refer to the following sample integration code and hook usage.
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { WagmiProvider } from 'wagmi'
import { CAProvider } from '@arcana/ca-wagmi'
import App from "./App.tsx";
import { config } from "./utils/config";
const queryClient = new QueryClient()
createRoot(document.getElementById("root")!).render(
<StrictMode>
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<CAProvider>
<App />
</CAProvider>
</QueryClientProvider>
</WagmiProvider>
</StrictMode>
);
import "./App.css";
import { useAccount } from "wagmi";
import { Account } from "./account";
import { WalletOptions } from "./wallet-options";
function ConnectWallet() {
const { isConnected } = useAccount();
if (isConnected) return <Account />;
return <WalletOptions />;
}
function App() {
return (
<div className="min-h-screen bg-white dark:bg-gray-900 flex">
<div className=" align-center m-auto min-w-md max-w-md p-6 bg-white border border-gray-200 rounded-lg shadow-sm dark:bg-gray-800 dark:border-gray-700">
<ConnectWallet />
</div>
</div>
);
}
export default App;
import {
useAccount,
useDisconnect,
useEnsName,
useSwitchChain,
// useSendTransaction //DO NOT use from the wagmi SDK
} from "wagmi";
import {
useBalance,
useSendTransaction, //Note: Use from ca-wagmi SDK
useWriteContract,
useUnifiedBalance,
} from "@arcana/ca-wagmi";
import { useState } from "react";
import Decimal from "decimal.js";
import { erc20Abi } from "viem";
export function Account() {
const { sendTransaction } = useSendTransaction();
const [allLoading, setLoading] = useState(false);
const { address } = useAccount();
const { disconnect } = useDisconnect();
const { data: ensName } = useEnsName({ address });
const { showBalance } = useBalance();
const { loading, getAssetBalance } = useUnifiedBalance();
if (!loading) {
console.log({ assetBalance: getAssetBalance("ETH") });
}
const { switchChainAsync } = useSwitchChain();
const { writeContract } = useWriteContract();
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setLoading(true);
const form = e.currentTarget;
try {
const formData = new FormData(form);
const toFV = formData.get("to");
const chainFV = formData.get("chain");
const assetFV = formData.get("asset");
const amountFV = formData.get("amount");
if (!toFV || !chainFV || !assetFV || !amountFV) {
throw new Error("missing params");
}
const to = toFV as `0x${string}`;
const chain = Number(chainFV);
const asset = assetFV as "usdc" | "usdt" | "eth";
await switchChainAsync({ chainId: chain });
let amount = new Decimal(amountFV as string);
if (asset.toLowerCase() === "ETH".toLowerCase()) {
amount = amount.mul(new Decimal(10).pow(18));
const value = BigInt(amount.toString());
sendTransaction(
{
to,
value,
},
{
onSuccess(hash) {
createSuccessToast(chain, hash);
form.reset();
setLoading(false);
console.log("success");
},
onSettled() {
console.log("settled");
},
onError(error) {
console.log({ error });
form.reset();
setLoading(false);
},
}
);
} else {
const chainData = chainToCurrency[chain];
const s = chainData[asset === "usdc" ? 0 : 1];
if (!s) {
throw new Error("asset not supported");
}
writeContract(
{
address: s,
abi: erc20Abi,
functionName: "transfer",
args: [to, BigInt(amount.mul(new Decimal(10).pow(6)).toString())],
},
{
onSuccess(hash) {
createSuccessToast(chain, hash);
form.reset();
setLoading(false);
console.log("success");
},
onError(error) {
form.reset();
setLoading(false);
console.log({ error });
},
}
);
}
} catch (e) {
form.reset();
console.log({ e });
setLoading(false);
}
};
return (
<>
{loading ? (
<div>
<p>Loading...</p>
</div>
) : (
<>
<p>
{address && ensName ? `${ensName} (${address})` : address}
</p>
<div>
<button onClick={() => disconnect()}>
Disconnect
</button>
<button onClick={() => showModal()}> //Display Unified Balance
Show balances
</button>
</div>
<div className="mb-4 m-auto"></div>
<form onSubmit={handleSubmit}>
<div>
<label>
To
</label>
<input
name="to"
type="text"
placeholder="0x..."
required
/>
</div>
<div>
<label>
Destination Chain
</label>
<select
required
name="chain"
id="chain"
defaultValue={""}
>
<option value="" disabled>
Select a chain
</option>
<option value="42161">Arbitrum One</option>
<option value="59144">Linea</option>
<option value="534352">Scroll</option>
<option value="10">Optimism</option>
<option value="8453">Base</option>
<option value="1">Ethereum</option>
<option value="137">Polygon POS</option>
</select>
</div>
<div>
<label>
Asset
</label>
<select
name="asset"
id="asset"
defaultValue={""}
>
<option value="" disabled>
Select an asset
</option>
<option value="usdt">USDT</option>
<option value="usdc">USDC</option>
<option value="eth">ETH</option>
</select>
</div>
<div className="mb-5">
<label>
Amount
</label>
<input
name="amount"
type="text"
id="amount"
required
/>
</div>
<button
type="submit"
disabled={allLoading}
>
{allLoading ? "Loading..." : "Submit"}
</button>
</form>
</>
)}
</>
);
}
import { http, createConfig } from "wagmi";
import {
mainnet,
optimism,
base,
arbitrum,
scroll,
linea,
polygon,
} from "wagmi/chains";
import { injected } from "wagmi/connectors";
export const config = createConfig({
chains: [mainnet, optimism, arbitrum, base, scroll, linea, polygon],
connectors: [injected()],
transports: {
[mainnet.id]: http(),
[optimism.id]: http(),
[arbitrum.id]: http(),
[base.id]: http(),
[scroll.id]: http(),
[linea.id]: http(),
[polygon.id]: http(),
},
});
import * as React from "react";
import { Connector, useConnect } from "wagmi";
function WalletOption({
connector,
onClick,
}: {
connector: Connector;
onClick: () => void;
}) {
const [ready, setReady] = React.useState(false);
React.useEffect(() => {
(async () => {
const provider = await connector.getProvider();
setReady(!!provider);
})();
}, [connector]);
return (
<>
<div>
<button
disabled={!ready}
type="button"
onClick={onClick}
>
<img
src={connector.icon}
aria-hidden="true"
/>
{connector.name}
</button>
</div>
</>
);
}
export function WalletOptions() {
const { connectors, connect } = useConnect();
return (
<>
<h3>
Wallets
</h3>
<hr></hr>
{connectors
.filter((c) => c.id !== "injected")
.map((connector) => (
<WalletOption
key={connector.uid}
connector={connector}
onClick={() => connect({ connector })}
/>
))}
</>
);
}
Hooks
The Arcana CA Wagmi SDK replaces useSendTranaction
and useWriteContract
hooks of the wagmi
library. In addition, it provides hooks for managing unified balance.
Wagmi Hooks
Replace the following hooks used in the app from the Wagmi library with those from the Arcana CA Wagmi SDK package:
import { useSendTransaction, useWriteContract } from "@arcana/ca-wagmi";
// Replace the `wagmi` APIs `useSendTransaction` and `useSendTransactionAsync`
const { sendTransaction, sendTransactionAsync } = useSendTransaction();
// Replace the wagmi APIs `useWriteContract` and `useWriteContractAsync`
const { writeContract, writeContractAsync } = useWriteContract();
Arcana Hooks
Use these Arcana hooks to access unified balance via the plug-and-play widget. Additionally, you can enable chain abstracted bridge and transfer functions through useCAFns
.
useBalance
- to get the unified balance value across all supported chains for the specified token stringuseBalances
- to get the unified balance values across all supported chains for all supported tokens associated with the EOAuseBalanceModal
- to display or hide the unified balance popup widgetuseCAFn()
- for chain abstracted bridging and token transfer functionality
useBalance
useBalance({ symbol: string })
symbol
: Required parameter of type string
with the value equal to one of the supported currency/token symbol.
useBalance()
returns response contains the following fields:
Parameter | Type |
---|---|
loading | boolean |
value | { symbol: string, decimals: number, formatted: string, value: bigint} \| null |
error | Error \| null |
import { useBalance } from "@arcana/ca-wagmi"
const balance = useBalance({ symbol: "eth" })
Sample useBalance
Response
{
loading: false,
value: {
symbol: "ETH",
decimals: 18,
formatted: "0.000785657313049966",
value: 785657313049966n
},
error: null
}
useBalances
useBalances()
returns response contains the following fields:
Parameter | Type |
---|---|
loading | boolean |
value | UseBalanceValue[] \| null |
error | Error \| null |
import { useBalances } from "@arcana/ca-wagmi"
const balances = useBalances()
Sample useBalances
Response
{
loading: false,
value: [{
symbol: "ETH",
decimals: 18,
formatted: "0.000785657313049966"
value: 785657313049966n,
breakdown: [{
chain: {
id: 1,
name: "Ethereum",
logo: "..."
},
formatted: "0.000785657313049966",
address: "0x0000000000000000000000000000000000000000",
value: 785657313049966n
}]
}],
error: null
}
useBalanceModal
useBalanceModal()
returns response contains the following fields:
Field | Type |
---|---|
showModal | () => void |
hideModal | () => void |
import { useBalanceModal } from "@arcana/ca-wagmi"
const { showModal, hideModal } = useBalanceModal()

useCAFn
The useCAFn()
response contains the following fields:
Parameter | Type |
---|---|
bridge | ({ token: string, amount: string, chain: number }) => Promise<unknown> |
transfer | ({ token: string, amount: string, chain: number, to: "0x${string}" }) => Promise<unknown> |
import { useCAFn } from "@arcana/ca-wagmi"
const { bridge, transfer } = useCAFn()
await bridge({
token: "usdt",
amount: "1.5",
chain: 42161
})
const hash = await transfer({to: "0x80129F3d408545e51d051a6D3e194983EB7801e8",
token: "usdt",
amount: "1.5",
chain: 10
})

See Also
Arcana CA Wagmi SDK Quick Links