npm package: @gearbox-protocol/auth-kit
Description: Wallet connection, signing and authentication SDK for Gearbox Protocol
Latest version: 1.5.2

# @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

```bash
pnpm add @gearbox-protocol/auth-kit viem wagmi @tanstack/react-query
```

## Quick Start

### Option 1: Use with existing WagmiProvider (Recommended)

If your app already has `WagmiProvider` and `QueryClientProvider`, auth-kit hooks work directly:

```tsx
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:

```tsx
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

```typescript
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

```typescript
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.

```typescript
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.

```typescript
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.

```typescript
import { useWalletType } from "@gearbox-protocol/auth-kit/react";

const { walletType, isLoading, isContract, isEOA } = useWalletType();
// walletType: "EOA" | "UNKNOWN_CONTRACT" | "UNKNOWN"
```

### `useConnection()`

Get current connection state.

```typescript
import { useConnection } from "@gearbox-protocol/auth-kit/react";

const { address, chainId, isConnected, isConnecting, connector } = useConnection();
```

### `useWallet()`

Get wallet client for signing.

```typescript
import { useWallet } from "@gearbox-protocol/auth-kit/react";

const { address, walletClient, isConnected, isLoading } = useWallet();
```

### `useWalletActions()`

Wallet connection actions.

```typescript
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.

```typescript
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.

```typescript
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.

```typescript
import { useIsSafeDomain } from "@gearbox-protocol/auth-kit/react";

const isSafe = useIsSafeDomain();
```

## Core API (Framework-agnostic)

### Agreement Service

```typescript
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

```typescript
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

```typescript
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

```typescript
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

```typescript
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

```typescript
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

```typescript
// 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

```typescript
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

```typescript
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

```typescript
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](/ContributionAgreement) for comprehensive understanding. [Let's innovate together!]