@gerritsen/supra-connect
v0.0.6
Published
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.
Maintainers
Readme
@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
npm install react react-dom @gerritsen/supra-connectOr with your favorite package manager:
pnpm install react react-dom @gerritsen/supra-connect
yarn add react react-dom @gerritsen/supra-connectThe 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
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):
<SupraConnectProvider rpcUrl="https://rpc-testnet.supra.com">
{/* Your app */}
</SupraConnectProvider>Or use a custom RPC:
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:
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.
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.
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.
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
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.
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:
// 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:
const result = await sendTransaction({
payload: {
moduleAddress: "0x1",
moduleName: "pbo_delegation_pool",
functionName: "add_stake",
arguments: [
"0x72b93dccbda04c9caf1b8726d96cb28edee5feceb85e32db318dd1eea4320331", // Raw string!
"734356207542" // Raw number string!
]
}
});✅ CORRECT:
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:
const result = await sendTransaction(request);
console.log("Transaction result:", JSON.stringify(result, null, 2));
// Check result.error and result.reason for detailsFAQ
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!
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 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:
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:
- Serializing all arguments with BCS (see above)
- Checking the response - log
result.errorandresult.reason - Using the correct module path - address and name must match the Move contract
License
MIT © 2024 Martin Gerritsen
You can use, modify, and redistribute this library freely. Just include the copyright notice!
See LICENSE for details.
