npm package: @gerritsen/supra-connect
Description: Custom React wallet connector for Supra L1 blockchain. Native support for Starkey and Ribbit wallets with a unified API. Built with care for the Supra ecosystem.
Author: Martin Gerritsen
Latest version: 0.0.11

# @gerritsen/supra-connect

A custom-built React wallet connector for the Supra L1 blockchain. Native support for Starkey and Ribbit wallets with a unified API. Built with care and passion for the Supra ecosystem.

## Installation

```bash
npm install @gerritsen/supra-connect
```

Or with your favorite package manager:

```bash
pnpm install @gerritsen/supra-connect
yarn add @gerritsen/supra-connect
```

The package is a React library and requires React 18+ as a peer dependency. If you're already using React in your project, you're all set!

## Features

- ✨ **Unified wallet API** - Single interface for Starkey and Ribbit wallets
- 🔐 **Full transaction support** - Send transfers, call contracts, stake, swap, and more
- 💬 **Message signing** - Sign and verify messages natively
- 🎨 **Pre-built components** - Production-ready connect button component
- 🪝 **React hook** - `useSupraConnect()` hook for complete wallet management
- ⚡ **Automatic wallet detection** - Detects installed wallets at runtime
- 🔧 **Custom RPC configuration** - Support for mainnet, testnet, and custom RPC endpoints
- 💯 **Built for Supra** - Optimized from the ground up for the Supra L1 ecosystem

## Quick Start

### Step 1: Wrap your app with the provider

```tsx
import '@gerritsen/supra-connect/styles.css';
import { SupraConnectProvider, SupraConnectButton } from '@gerritsen/supra-connect';

export function App() {
  return (
    <SupraConnectProvider>
      <div>
        <h1>My Supra dApp</h1>
        <SupraConnectButton
          dappMetadata={{
            name: "My dApp",
            description: "My awesome Supra dApp",
            url: "https://mydapp.com",
          }}
        />
      </div>
    </SupraConnectProvider>
  );
}
```

The provider initializes wallet detection and makes the `useSupraConnect` hook available throughout your app.

#### Custom RPC Configuration

By default, the provider uses the Supra mainnet RPC. To use a different RPC endpoint (e.g., testnet):

```tsx
<SupraConnectProvider rpcUrl="https://rpc-testnet.supra.com">
  {/* Your app */}
</SupraConnectProvider>
```

Or use a custom RPC:

```tsx
import { DEFAULT_RPC_URL } from '@gerritsen/supra-connect';

<SupraConnectProvider rpcUrl="https://your-custom-rpc.com">
  {/* Your app */}
</SupraConnectProvider>
```

### Step 2: Use the `useSupraConnect` hook

Once a wallet is connected, use the hook to send transactions:

```tsx
import { useSupraConnect } from '@gerritsen/supra-connect';
import { BCS, HexString } from 'supra-l1-sdk';

export function MyComponent() {
  const { isConnected, connectedWallet, sendTransaction } = useSupraConnect();

  const handleSendTransfer = async () => {
    if (!isConnected) {
      alert('Please connect your wallet first');
      return;
    }

    // Serialize the arguments (receiver and amount)
    const receiverBytes = new HexString('0x1234...').toUint8Array();
    const amountBytes = BCS.bcsSerializeUint64(BigInt(1000000000)); // 1 SUPRA

    // Send the transaction
    const result = await sendTransaction({
      payload: {
        moduleAddress: '0x1',
        moduleName: 'supra_account',
        functionName: 'transfer',
        typeArguments: [],
        arguments: [receiverBytes, amountBytes],
      },
    });

    if (result.success) {
      alert(`Transfer successful! Hash: ${result.txHash}`);
    } else {
      alert(`Transfer failed: ${result.error}`);
    }
  };

  return (
    <div>
      <p>Wallet: {connectedWallet?.walletAddress}</p>
      <button onClick={handleSendTransfer}>Send 1 SUPRA</button>
    </div>
  );
}
```

## API Reference

### useSupraConnect()

The main hook to access wallet state and methods.

```typescript
const {
  // Wallet State
  connectedWallet,      // { walletAddress, type: 'starkey' | 'ribbit' } or null
  isConnected,          // boolean - is wallet connected?
  isConnecting,         // boolean - currently connecting?
  connectionError,      // string | null - any connection errors
  availableWallets,     // Array - detected wallets ['starkey', 'ribbit']

  // Connection Methods
  connectStarkey,       // () => Promise<void>
  connectRibbit,        // () => Promise<void>
  disconnect,           // () => Promise<void>

  // Wallet Operations (main methods you'll use)
  sendTransaction,      // (request) => Promise<TransactionResult>
  signMessage,          // (message: string) => Promise<SignMessageResult>

  // Info Methods
  getPublicAddress,     // (chainType?: string) => string | null
  getRpcUrl,            // () => string - get configured RPC URL

  // Utilities
  clearError,           // () => void - clear error messages
} = useSupraConnect();
```

### sendTransaction()

Send any transaction to the blockchain.

```typescript
const result = await sendTransaction({
  payload: {
    moduleAddress: '0x1',           // Module address
    moduleName: 'supra_account',    // Module name
    functionName: 'transfer',       // Function to call
    typeArguments: [],              // Type args (for generics)
    arguments: [bytes1, bytes2],    // Pre-serialized arguments as Uint8Array
  },
  options: {
    maxGasAmount: '10000',          // Optional
    gasUnitPrice: '100',            // Optional
  },
});

// Result
if (result.success) {
  console.log(result.txHash);  // Transaction was successful
} else {
  console.log(result.error);   // Transaction failed
}
```

### signMessage()

Sign a message with the connected wallet.

```typescript
const result = await signMessage('Hello, Supra!');

if (result.success) {
  console.log(result.signature);  // Hex string of signature
} else {
  console.log(result.reason);     // Why signing failed
}
```

## Common Examples

### Transfer Tokens

```tsx
import { useSupraConnect } from '@gerritsen/supra-connect';
import { BCS, HexString } from 'supra-l1-sdk';

const { sendTransaction } = useSupraConnect();

const recipient = '0x1234...';
const amountSupra = '1';  // 1 SUPRA

const result = await sendTransaction({
  payload: {
    moduleAddress: '0x1',
    moduleName: 'supra_account',
    functionName: 'transfer',
    typeArguments: [],
    arguments: [
      new HexString(recipient).toUint8Array(),
      BCS.bcsSerializeUint64(BigInt(1000000000)), // 1 SUPRA = 1e8 units (8 decimals)
    ],
  },
});

console.log(result.success ? `Sent! ${result.txHash}` : `Failed: ${result.error}`);
```

## Components

### SupraConnectButton

A pre-built button that handles wallet connection/disconnection.

```tsx
import { SupraConnectButton } from '@gerritsen/supra-connect';
import '@gerritsen/supra-connect/styles.css';

export function Header() {
  return (
    <header>
      <h1>My dApp</h1>
      <SupraConnectButton
        dappMetadata={{
          name: 'My dApp',
          description: 'My awesome Supra dApp',
          url: 'https://mydapp.com',
        }}
      />
    </header>
  );
}
```

**What it does:**
- Shows "Connect Wallet" button if not connected
- Shows connected wallet address if connected
- Auto-detects Starkey and Ribbit wallets

**Props:**

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `dappMetadata` | `DappMetadata` | - | Wallet metadata (name, description, url, icon) |
| `width` | `string` | `"100%"` | Button width (accepts %, px, rem, etc.) |

**Examples:**

```tsx
// Full width (default)
<SupraConnectButton
  dappMetadata={{ name: 'My dApp', description: 'Demo' }}
/>

// Custom width with pixels
<SupraConnectButton
  width="300px"
  dappMetadata={{ name: 'My dApp', description: 'Demo' }}
/>

// Custom width with percentage
<SupraConnectButton
  width="50%"
  dappMetadata={{ name: 'My dApp', description: 'Demo' }}
/>

// Custom width with rem units
<SupraConnectButton
  width="20rem"
  dappMetadata={{ name: 'My dApp', description: 'Demo' }}
/>
```

## Troubleshooting

### Transaction fails silently

**Symptom:** `sendTransaction()` completes but nothing happens, or you get `{ success: false }` with no clear error.

**Common cause:** Arguments are not properly serialized. The package expects arguments to be **Uint8Array bytes**, not raw strings or numbers.

**❌ WRONG:**
```tsx
const result = await sendTransaction({
  payload: {
    moduleAddress: "0x1",
    moduleName: "pbo_delegation_pool",
    functionName: "add_stake",
    arguments: [
      "0x72b93dccbda04c9caf1b8726d96cb28edee5feceb85e32db318dd1eea4320331", // Raw string!
      "734356207542" // Raw number string!
    ]
  }
});
```

**✅ CORRECT:**
```tsx
import { BCS, HexString } from 'supra-l1-sdk';

const result = await sendTransaction({
  payload: {
    moduleAddress: "0x1",
    moduleName: "pbo_delegation_pool",
    functionName: "add_stake",
    typeArguments: [],
    arguments: [
      new HexString("0x72b93dccbda04c9caf1b8726d96cb28edee5feceb85e32db318dd1eea4320331").toUint8Array(),
      BCS.bcsSerializeUint64(BigInt("734356207542"))
    ]
  }
});

// Always check the response!
if (!result.success) {
  console.error("Transaction failed:", result.reason);
}
```

**Solution:** Always serialize arguments using BCS before sending.

### Getting the actual error message

If a transaction fails, always log the full response:

```tsx
const result = await sendTransaction(request);
console.log("Transaction result:", JSON.stringify(result, null, 2));
// Check result.error and result.reason for details
```

## FAQ

**Q: Do I need both wallets installed?**
No! The library auto-detects which wallets are available. It works with just Starkey, just Ribbit, or both.

**Q: What chains does this support?**
Currently Supra L1 mainnet. The library handles all network setup automatically.

**Q: How do I serialize arguments for custom functions?**
Use the `supra-l1-sdk` utilities. **Always serialize arguments - never pass raw strings!**

```typescript
import { BCS, HexString } from 'supra-l1-sdk';

// For addresses/hex values
new HexString("0x1234...").toUint8Array()

// For strings
BCS.bcsSerializeStr("hello")

// For u64 numbers
BCS.bcsSerializeUint64(BigInt(1000000000))

// For u8 numbers
BCS.bcsSerializeU8(255)

// For booleans
BCS.bcsSerializeBool(true)
```

See the [supra-l1-sdk documentation](https://github.com/supra-labs/supra-l1-sdk) for more types.

**Q: Can I use this with Next.js?**
Yes! The library is SSR-safe. It checks `typeof window` before accessing wallet APIs. Wrap your provider in a `'use client'` component for App Router.

**Q: How do I handle errors?**
All errors are returned in the result object, never thrown:
```tsx
const result = await sendTransaction(...);
if (!result.success) {
  console.error("Error:", result.error);
  console.error("Reason:", result.reason);
}
```

**Q: My transaction is failing but I don't see an error message**
Make sure you're:
1. **Serializing all arguments** with BCS (see above)
2. **Checking the response** - log `result.error` and `result.reason`
3. **Using the correct module path** - address and name must match the Move contract

## Changelog

**v0.0.11** (2026-01-03) - Replaced `supra-l1-sdk` with `supra-l1-sdk-core` for 64% smaller dependencies (~2.88 MB reduction)

**v0.0.10** (2025-12-26) - Removed dead code and optimized imports for better tree-shaking (~0.83 KB bundle reduction)

**v0.0.9** (2025-12-23) - Added shared utilities module, removed ~250 lines of duplicate code across wallets

**v0.0.8** (2025-12-23) - Added localStorage persistence for Starkey wallet (10-day expiry, auto-restore on refresh)

**v0.0.7** (2025-12-08) - Cleaned up public API surface by removing internal exports

**v0.0.5** (2025-12-01) - Exported `ConnectedWallet`, `WalletInfo`, and `WalletType` types for better TypeScript support

**v0.0.4** (2025-12-01) - Fixed modal rendering using React Portal for proper full-viewport display

**v0.0.3** (2025-12-01) - Added per-wallet connection state tracking (individual loading states)

**v0.0.2** (2025-12-01) - Added error utility module, removed ~114 lines of duplicate code

**v0.0.1** (2025-11-18) - Initial release with Starkey and Ribbit wallet support

## License

MIT © 2025 Martin Gerritsen

You can use, modify, and redistribute this library freely. Just include the copyright notice!

See [LICENSE](./LICENSE) for details.