@gearbox-protocol/auth-kit
v1.3.0
Published
Wallet connection, signing and authentication SDK for Gearbox Protocol
Readme
@gearbox-protocol/auth-kit
Wallet connection, signing and authentication SDK for Gearbox Protocol applications.
Features
- 🔌 RPC Configuration — Pre-configured DRPC, Alchemy, and custom RPC providers
- ✍️ Agreement Signing — Legal agreement signing and verification with react-query caching
- 📜 ERC-2612 Permits — Token approval without gas
- 🔐 SIWE Utilities — Sign-In with Ethereum message helpers
- 🔒 Contract Signatures — Safe and other contract wallet signature verification
- ⚛️ React Hooks — Easy-to-use React hooks with react-query for caching
- 🎨 UI Agnostic — Works with RainbowKit, ConnectKit, or custom UI
Installation
pnpm add @gearbox-protocol/auth-kit viem wagmi @tanstack/react-queryQuick Start
Option 1: Use with existing WagmiProvider (Recommended)
If your app already has WagmiProvider and QueryClientProvider, auth-kit hooks work directly:
import { WagmiProvider } from "wagmi";
import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
import { useAgreement, useWalletType } from "@gearbox-protocol/auth-kit/react";
const queryClient = new QueryClient();
function App() {
return (
<WagmiProvider config={wagmiConfig}>
<QueryClientProvider client={queryClient}>
<MyComponent />
</QueryClientProvider>
</WagmiProvider>
);
}
function MyComponent() {
// Auth-kit hooks work without AuthKitProvider!
// Uses Gearbox default endpoints automatically
const { status, signAgreement } = useAgreement({ config: {} });
const { walletType, isContract } = useWalletType();
return <div>...</div>;
}Option 2: Use AuthKitProvider (All-in-one)
For new projects without wagmi setup:
import { AuthKitProvider } from "@gearbox-protocol/auth-kit/react";
import { createAuthKitConfig } from "@gearbox-protocol/auth-kit";
const { wagmiConfig, authKitConfig } = createAuthKitConfig({
chains: [mainnet, optimism],
transports: { ... },
projectId: "YOUR_WC_PROJECT_ID",
appName: "My App",
});
function App() {
return (
<AuthKitProvider config={authKitConfig} wagmiConfig={wagmiConfig}>
<MyComponent />
</AuthKitProvider>
);
}RPC Configuration
import {
createFullRpcList,
createTransportsFromRpcList,
} from "@gearbox-protocol/auth-kit";
import { mainnet, optimism, arbitrum } from "viem/chains";
const chains = [mainnet, optimism, arbitrum];
// Simple setup with DRPC
const rpcList = createFullRpcList(chains, {
drpcApiKey: process.env.DRPC_API_KEY,
});
// Create wagmi transports
const transports = createTransportsFromRpcList(rpcList);With RainbowKit
import { connectorsForWallets } from "@rainbow-me/rainbowkit";
import { createConfig } from "wagmi";
import { createFullRpcList, createTransportsFromRpcList } from "@gearbox-protocol/auth-kit";
const chains = [mainnet, optimism, arbitrum];
const rpcList = createFullRpcList(chains, { drpcApiKey: "..." });
const transports = createTransportsFromRpcList(rpcList);
const connectors = connectorsForWallets([
{
groupName: "Popular",
wallets: [rabbyWallet, metaMaskWallet, walletConnectWallet],
},
], {
projectId: "YOUR_WC_PROJECT_ID",
appName: "My App",
});
const config = createConfig({
chains,
transports,
connectors,
});React Hooks
All hooks use react-query for caching and synchronization between components.
useAgreement(options)
Legal agreement signing hook with caching.
import { useAgreement } from "@gearbox-protocol/auth-kit/react";
const {
status, // "ALLOWED" | "NOT_SIGNED" | "BLOCKED" | "AWAITING_SIGNATURE"
isLoading, // Check in progress
isSigning, // Signing in progress
error,
checkAgreement, // Manual check
signAgreement, // Sign the agreement
hasV2Signature, // Has legacy v2 signature (needs re-sign)
legalMessage, // Legal message text
legalMessageVersion,
allStatuses, // All cached statuses (for multiple accounts)
} = useAgreement({
config: {
// Uses Gearbox defaults if not specified:
// signatureEndpoint: "https://auth.gearbox.foundation"
// accessCheckEndpoint: "https://app.gearbox.finance/api/check-access"
legalMessage: { version: 3, text: "..." }, // Optional custom message
},
autoCheck: true, // Auto-check on mount (default: true)
});useBlockedRegion(config)
Check if user's region is blocked.
import { useBlockedRegion } from "@gearbox-protocol/auth-kit/react";
// Uses default endpoint: https://app.gearbox.finance/api/check-access
const { isBlocked, isLoading, isError } = useBlockedRegion({});
// Or with custom endpoint
const { isBlocked } = useBlockedRegion({
accessCheckEndpoint: "https://custom.endpoint.com/check-access",
});useWalletType(account?)
Detect wallet type (EOA or Contract) with caching.
import { useWalletType } from "@gearbox-protocol/auth-kit/react";
const { walletType, isLoading, isContract, isEOA } = useWalletType();
// walletType: "EOA" | "UNKNOWN_CONTRACT" | "UNKNOWN"useConnection()
Get current connection state.
import { useConnection } from "@gearbox-protocol/auth-kit/react";
const { address, chainId, isConnected, isConnecting, connector } = useConnection();useWallet()
Get wallet client for signing.
import { useWallet } from "@gearbox-protocol/auth-kit/react";
const { address, walletClient, isConnected, isLoading } = useWallet();useWalletActions()
Wallet connection actions.
import { useWalletActions } from "@gearbox-protocol/auth-kit/react";
const {
connect,
disconnect,
switchChain,
connectors,
isConnecting,
isDisconnecting,
isSwitching,
connectError,
switchError,
} = useWalletActions();usePermit(options)
ERC-2612 permit signing hook.
import { usePermit } from "@gearbox-protocol/auth-kit/react";
const { signPermit, isLoading, error } = usePermit({
walletClient,
publicClient,
chainId,
account,
});
const permit = await signPermit({
token: tokenAddress,
tokenInfo: { type: "amount", name: "USDC", version: "1" },
spender: spenderAddress,
value: amount,
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
});useSiwe(options)
Sign-In with Ethereum hook.
import { useSiwe } from "@gearbox-protocol/auth-kit/react";
const { signIn, isLoading, error, nonce, refreshNonce } = useSiwe({
walletClient,
account,
chainId,
domain: "app.example.com",
statement: "Sign in to My App",
expirationMinutes: 60,
});
const result = await signIn();
// { message: "...", signature: "0x..." }useIsSafeDomain(customDomains?)
Check if running in Safe iframe.
import { useIsSafeDomain } from "@gearbox-protocol/auth-kit/react";
const isSafe = useIsSafeDomain();Core API (Framework-agnostic)
Agreement Service
import {
AgreementService,
LEGAL_MESSAGES,
GEARBOX_AUTH_ENDPOINT,
GEARBOX_ACCESS_CHECK_ENDPOINT,
} from "@gearbox-protocol/auth-kit";
// Uses Gearbox default endpoints automatically
const agreementService = new AgreementService({
legalMessage: LEGAL_MESSAGES[3],
});
// Or with custom endpoints
const customService = new AgreementService({
signatureEndpoint: "https://custom.auth.com",
accessCheckEndpoint: "https://custom.auth.com/check-access",
});
// Check if agreement was signed
const result = await agreementService.checkAgreement({
account: "0x...",
contractCheckOptions: { ... }, // For Safe wallets
});
// Sign the agreement
const signResult = await agreementService.signAgreement({
account: "0x...",
signer: walletClient,
chainId: 1,
});
// Access default endpoints
console.log(GEARBOX_AUTH_ENDPOINT); // "https://auth.gearbox.foundation"
console.log(GEARBOX_ACCESS_CHECK_ENDPOINT); // "https://app.gearbox.finance/api/check-access"Contract Signature Verification
import { ContractSignatureUtils, addressIsContract } from "@gearbox-protocol/auth-kit";
// Check if address is a contract
const isContract = await addressIsContract(address, publicClient);
// Compute Safe-compatible message hash
const hash = ContractSignatureUtils.computeHashOffChain(
"Message to sign",
chainId,
walletAddress
);
// Verify signature on-chain
const isValid = await ContractSignatureUtils.checkSignatureOnContract(
walletAddress,
hash,
publicClient
);Permit Service
import { PermitService } from "@gearbox-protocol/auth-kit";
const nonce = await PermitService.getNonce(tokenAddress, owner, publicClient);
const permit = await PermitService.signPermit({
signer: walletClient,
chainId: 1,
token: tokenAddress,
info: { type: "amount", name: "USDC", version: "1" },
owner: "0x...",
spender: "0x...",
value: 1000000n,
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
nonce,
});SIWE Utilities
import { createSiweMessage, generateNonce, parseSiweMessage } from "@gearbox-protocol/auth-kit";
const message = createSiweMessage({
domain: "app.example.com",
address: "0x...",
uri: "https://app.example.com",
chainId: 1,
nonce: generateNonce(),
statement: "Sign in to My App",
});
const signature = await walletClient.signMessage({ message, account });
const parsed = parseSiweMessage(message);RPC Configuration
import {
createFullRpcList,
createDrpcRpcList,
createAlchemyRpcList,
createTransportsFromRpcList,
mergeRpcLists,
DEFAULT_DRPC_CHAIN_NAMES,
DEFAULT_ALCHEMY_NETWORK_NAMES,
} from "@gearbox-protocol/auth-kit";
const rpcList = createFullRpcList(chains, {
drpcApiKey: "...",
alchemyApiKey: "...",
customRpcs: { 12345: [{ url: "https://my-rpc.com" }] },
});
const transports = createTransportsFromRpcList(rpcList);Connector Utilities
import {
isSafeDomain,
isSafeAppsSDK,
isMetaMask,
isWalletConnect,
isRabby,
isBinanceSDK,
configureConnectors,
DEFAULT_SAFE_DOMAINS,
} from "@gearbox-protocol/auth-kit";
// Check connector type
if (isSafeAppsSDK(connector)) {
// Handle Safe wallet
}
// Configure custom Safe domains
configureConnectors({
safeDomains: [...DEFAULT_SAFE_DOMAINS, /^safe\.mycompany\.com$/],
});Package Exports
// Core (framework-agnostic)
import {
// RPC
createFullRpcList,
createDrpcRpcList,
createAlchemyRpcList,
createTransportsFromRpcList,
mergeRpcLists,
// Connectors
configureConnectors,
isSafeDomain,
isSafeAppsSDK,
isMetaMask,
// Agreement
AgreementService,
AgreementError,
ContractSignatureUtils,
addressIsContract,
LEGAL_MESSAGES,
GEARBOX_AUTH_ENDPOINT,
GEARBOX_ACCESS_CHECK_ENDPOINT,
// Signing
PermitService,
createSiweMessage,
parseSiweMessage,
generateNonce,
// Config
createWagmiConfig,
createAuthKitConfig,
} from "@gearbox-protocol/auth-kit";
// React hooks and providers
import {
// Hooks
useConnection,
useWallet,
useWalletActions,
useAgreement,
useBlockedRegion,
usePermit,
useSiwe,
useIsSafeDomain,
useWalletType,
// Provider (optional)
AuthKitProvider,
useAuthKitConfig,
} from "@gearbox-protocol/auth-kit/react";Usage Examples
Legal Agreement Flow
import { useAgreement } from "@gearbox-protocol/auth-kit/react";
function AgreementGuard({ children }) {
// Uses Gearbox default endpoints
const { status, isLoading, signAgreement, legalMessage } = useAgreement({
config: {},
});
if (isLoading) {
return <div>Checking agreement status...</div>;
}
if (status === "BLOCKED") {
return <div>Access denied for your region</div>;
}
if (status !== "ALLOWED") {
return (
<div>
<p>{legalMessage}</p>
<button onClick={signAgreement}>
{status === "AWAITING_SIGNATURE" ? "Sign in wallet..." : "Sign Agreement"}
</button>
</div>
);
}
return children;
}Safe Wallet Detection
import { useIsSafeDomain, useWalletType } from "@gearbox-protocol/auth-kit/react";
import { isSafeAppsSDK } from "@gearbox-protocol/auth-kit";
import { useAccount } from "wagmi";
function SafeAwareComponent() {
const { connector } = useAccount();
const isSafeDomain = useIsSafeDomain();
const { isContract } = useWalletType();
const isSafeWallet = isSafeDomain || (connector && isSafeAppsSDK(connector)) || isContract;
if (isSafeWallet) {
return <div>Connected via Safe - transactions will be queued</div>;
}
return <div>Connected via EOA wallet</div>;
}Permit Signing
import { usePermit } from "@gearbox-protocol/auth-kit/react";
function ApproveWithPermit() {
const { signPermit, isLoading } = usePermit({ ... });
const handleApprove = async () => {
const permit = await signPermit({
token: USDC_ADDRESS,
tokenInfo: { type: "amount", name: "USD Coin", version: "2" },
spender: SPENDER_ADDRESS,
value: parseUnits("1000", 6),
});
await contract.permitAndDeposit(permit);
};
return (
<button onClick={handleApprove} disabled={isLoading}>
Approve & Deposit
</button>
);
}Compatibility
This SDK works with:
- wagmi v2 — Required for wallet connection
- @tanstack/react-query v5 — Required for caching
- RainbowKit — Wallet UI (optional)
- ConnectKit — Wallet UI (optional)
- next-auth — Session management (optional, separate integration)
Important information for contributors
As a contributor to the Gearbox Protocol GitHub repository, your pull requests indicate acceptance of our Gearbox Contribution Agreement. This agreement outlines that you assign the Intellectual Property Rights of your contributions to the Gearbox Foundation. This helps safeguard the Gearbox protocol and ensure the accumulation of its intellectual property. Contributions become part of the repository and may be used for various purposes, including commercial. As recognition for your expertise and work, you receive the opportunity to participate in the protocol's development and the potential to see your work integrated within it. The full Gearbox Contribution Agreement is accessible within the repository for comprehensive understanding. [Let's innovate together!]
