Skip to content

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();
FieldTypeMeaning
addressstring | nullUser-facing wallet address for the primary network (Ethereum by default). null if no wallet yet.
walletsWalletInfo[]All wallets across configured networks (one per curve).
readybooleantrue after init() succeeded.
errorError | nullWhatever 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).

FieldRequiredNotes
chainyes'ethereum', 'polygon', 'arbitrum', 'base', 'optimism', 'bsc', 'avalanche', 'solana'.
toyesContract or recipient address.
datano0x-prefixed call data. Omit for pure native transfers.
valuenoDecimal wei as a string. Default '0'.
gasLimitnoDecimal gas units. Override when you know the estimate will revert (e.g. some bridge deposits).
previewno{ 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>
</>
);
}