React
The React entrypoint exposes a context provider and four hooks. The
provider owns one Sigil instance for the lifetime of its mount and
tears it down on unmount.
<SigilProvider config={...}>
Wrap the part of your tree that needs wallet access. Conventionally this is your whole app.
import { SigilProvider } from '@sigilkeys/sdk/react';
const config = { organizationId: 'org_xxx', publishableKey: 'pk_live_xxx', iframeUrl: 'https://wallet.sigilkeys.com', authMode: 'sigil' as const,};
export function Root({ children }: { children: React.ReactNode }) { return <SigilProvider config={config}>{children}</SigilProvider>;}The provider renders the iframe (mounted by the SDK) directly into
document.body by default. To mount it inside a specific node, pass
iframeContainer in config.
useWallet()
const { address, wallets, ready, error } = useWallet();| Field | Type | Meaning |
|---|---|---|
address | string | null | User-facing wallet address for the primary network (Ethereum by default). null if no wallet yet. |
wallets | WalletInfo[] | All wallets across configured networks (one per curve). |
ready | boolean | true after init() succeeded. |
error | Error | null | Whatever blew up during init(), or null. |
Re-renders only on transitions; subscribing components don’t re-render on every postMessage round-trip.
useSignMessage()
const { signMessage, isLoading } = useSignMessage();
<button disabled={isLoading} onClick={async () => { const sig = await signMessage('hello', { network: 'ethereum' }); console.log(sig); }}> Sign</button>signMessage(message, options?) returns the hex signature. Pass
{ network } to select which network’s key signs the message; defaults
to the primary network. isLoading is true while the iframe is
showing the confirmation modal and the user hasn’t yet approved or
rejected.
If the user rejects, the promise rejects with a SigilRejectedError.
useSignTypedData()
EIP-712 structured signing. Use this for off-chain orders, EIP-2612
permit, Permit2, SIWE, anything that asks for a typed-data signature.
const { signTypedData, isLoading } = useSignTypedData();
async function approve() { const { signature, digest } = await signTypedData({ domain: { name: 'USD Coin', version: '2', chainId: 42161, verifyingContract: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831', // USDC on Arbitrum }, types: { Permit: [ { name: 'owner', type: 'address' }, { name: 'spender', type: 'address' }, { name: 'value', type: 'uint256' }, { name: 'nonce', type: 'uint256' }, { name: 'deadline', type: 'uint256' }, ], }, primaryType: 'Permit', message: { owner, spender, value, nonce, deadline }, }); // Forward { signature, digest } to your backend (or the on-chain caller). // `digest` is the 32-byte EIP-712 hash that was actually signed — // useful for ecrecover-validating the signature before submitting.}Returns { signature, digest }. The signature is 65 bytes
(r || s || v) ready to split into the (v, r, s) triple that most
permit-style functions expect. digest lets you ecrecover the
signer server-side without re-implementing EIP-712 hashing.
If the user rejects, the promise rejects with a SigilRejectedError.
useSendTransaction()
Raw EIP-1559 send from the wallet’s EOA. The user pays gas from their wallet’s native balance on the target chain.
const { sendTransaction, isLoading } = useSendTransaction();
async function deposit() { const r = await sendTransaction({ chain: 'arbitrum', to: BRIDGE_CONTRACT, data: encodeDeposit(usdcAmount), // your ABI encoder value: '0', // wei as a decimal string preview: { title: 'Deposit to Hyperliquid', description: `${usdc(usdcAmount)} USDC`, }, }); toast(`Submitted: ${r.txHash}`);}Returns { chain, chainId, txHash, from }. from is the EOA the tx
was signed by. The function returns once the RPC accepted the broadcast;
finality is your responsibility (chains differ in confirmation times).
| Field | Required | Notes |
|---|---|---|
chain | yes | 'ethereum', 'polygon', 'arbitrum', 'base', 'optimism', 'bsc', 'avalanche', 'solana'. |
to | yes | Contract or recipient address. |
data | no | 0x-prefixed call data. Omit for pure native transfers. |
value | no | Decimal wei as a string. Default '0'. |
gasLimit | no | Decimal gas units. Override when you know the estimate will revert (e.g. some bridge deposits). |
preview | no | { title, description?, fields? } shown on the confirm screen. UX only — does not affect what gets signed. |
If the user rejects, the promise rejects with a SigilRejectedError.
Full app
import { SigilProvider, useWallet, useSignMessage } from '@sigilkeys/sdk/react';
function App() { return ( <SigilProvider config={{ organizationId: 'org_xxx', publishableKey: 'pk_live_xxx', iframeUrl: 'https://wallet.sigilkeys.com', authMode: 'sigil', }} > <Wallet /> </SigilProvider> );}
function Wallet() { const { address, ready, error } = useWallet(); const { signMessage, isLoading } = useSignMessage();
if (error) return <p>error: {error.message}</p>; if (!ready) return <p>loading...</p>;
return ( <> <p>{address}</p> <button disabled={isLoading} onClick={() => signMessage('hi')}> Sign </button> </> );}