
Vechain React Native Dev
- 65 installs
- 9 repo stars
- Updated June 11, 2026
- vechain/vechain-ai-skills
Helps with frontend development tasks.
About
vechain-react-native-dev is a Claude Code skill for frontend development. It helps solo builders move faster with AI-assisted coding.
- vechain-react-native-dev
- Frontend Development
- AI-coding skill
Vechain React Native Dev by the numbers
- 65 all-time installs (skills.sh)
- Ranked #1,179 of 2,245 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/vechain/vechain-ai-skills --skill vechain-react-native-devAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 65 |
|---|---|
| repo stars | ★ 9 |
| Last updated | June 11, 2026 |
| Repository | vechain/vechain-ai-skills ↗ |
What it does
Helps with frontend development tasks.
Files
React Native Wallet Link Skill
CRITICAL RULES
1. Read reference files FIRST. When the user's request involves any topic in the reference table below, read those files before doing anything else — before writing code, before making decisions. Briefly mention which files you are reading so the user can confirm the skill is active (e.g., "Reading wallet link API reference..."). 2. Information priority for VeChain topics: (a) Reference files in this skill — always the primary source. (b) VeChain MCP tools — use @vechain/mcp-server for on-chain data, transaction building, and live network queries; use Kapa AI MCP for VeChain documentation lookups. (c) Web search — only as a last resort, and only for topics NOT covered in the reference files. 3. Prefer working directly in the main conversation for VeChain tasks. Plan mode and subagents do not inherit skill context and may fall back to web search instead of using reference files. 4. After compaction or context loss, re-read this SKILL.md to restore awareness of the reference table and operating procedure before continuing work.
Scope
Use this Skill for React Native dApp development integrating with VeWorld wallet:
- Installing and configuring
@vechain/react-native-wallet-link VeWorldProvidersetup with deep link handling and event callbacksuseVeWorldWallethook — connect, disconnect, sign certificates, sign typed data, sign and send transactions- NaCl key pair generation, encrypted communication, payload decryption
- Deep link configuration for iOS (URL schemes, universal links) and Android (intent filters)
- State management for wallet sessions (key pair, session, address persistence)
- Multi-clause transaction signing via VeWorld
- Certificate signing (identification, verification, attestation)
- EIP-712 typed data signing
- Error handling for wallet responses
- Multi-network support (mainnet, testnet, solo)
For related topics, see companion skills:
- vechain-core — Core SDK usage, fee delegation, multi-clause patterns, dual-token model
- vechain-kit — VeChain Kit and dapp-kit packages: hooks, components, wallet connection, social login
- frontend — Generic frontend patterns: React Query, Turborepo, state management, Chakra UI
- smart-contract-development — Solidity, Hardhat, testing, security
Default stack
| Layer | Default | Alternative |
|---|---|---|
| Wallet link | @vechain/react-native-wallet-link | — |
| SDK | @vechain/sdk-core + @vechain/sdk-network | — |
| Framework | Expo (React Native) | bare React Native |
| State | Zustand + AsyncStorage | any persisted store |
| Node | Node 20 LTS (managed via nvm) | — |
Operating procedure
1. Check Node version
Before installing dependencies or running any command:
- Check if
.nvmrcexists in the project root. If yes, runnvm use. - If
.nvmrcdoes not exist, create one with20(Node 20 LTS) and runnvm use.
2. Detect project structure
- Expo project → use
expo-linkingfor deep link handling - Bare React Native → use
react-nativeLinkingAPI directly - Check for existing state management (Zustand, Redux, Context) and match it
3. Clarify before implementing
When the user's request is ambiguous or could be solved multiple ways, ask before building. Separate research from implementation:
- Which network? (mainnet/testnet/solo)
- Which operations? (connect only, signing, transactions)
- State management preference?
- Deep link scheme name?
4. Implement with VeChain-specific correctness
- Always install peer dependencies:
@vechain/sdk-core,@vechain/sdk-network,react-native-get-random-values,events - Import `react-native-get-random-values` before any NaCl usage — required for crypto in React Native
- Network: always explicit (
mainnet/testnet/solo) via the node URL passed toVeWorldProvider - Key pairs: generate with
nacl.box.keyPair(), store Base64-encoded viaencodeBase64()fromtweetnacl-util - Session persistence: persist keyPair, veWorldPublicKey, address, and session across app restarts
- Error handling: always check for
errorCodein wallet responses before processing decrypted data - Deep links: configure platform-specific URL schemes so VeWorld can redirect back to the app
5. Verify and deliver
A task is not complete until all applicable gates pass:
1. Code compiles — no build errors (npx expo start or equivalent succeeds) 2. Deep links configured — iOS Info.plist and/or Android intent filters set up 3. Risk notes documented — any signing, fee, or token-transfer implications are called out
Then provide:
- Files changed + diffs
- Install/build commands
- Deep link scheme configuration steps
- Risk notes for signing, fees, token transfers
Reference files
Read the matching files BEFORE doing anything else. See Critical Rules above.
| Topic | File | Read when user mentions... |
|---|---|---|
| API and hook reference | references/wallet-link-api.md | useVeWorldWallet, VeWorldProvider, connect, disconnect, signCertificate, signTypedData, signAndSendTransaction, key pair, encrypt, decrypt |
| Deep link and platform setup | references/deep-link-setup.md | deep link, URL scheme, universal link, iOS, Android, intent filter, redirect, Expo linking, app.json |
| Example integration | references/example-integration.md | example, demo, full app, tutorial, how to use, getting started, Zustand, state management, VET transfer |
Deep Link and Platform Setup
Overview
@vechain/react-native-wallet-link uses deep links for app-to-app communication with VeWorld. When your app requests a wallet operation, it opens VeWorld via a deep link. VeWorld processes the request and redirects back to your app using the configured redirectUrl.
How it works
1. Your app calls a hook method (e.g., connect(publicKey)) 2. The library constructs a VeWorld deep link URL with encrypted parameters 3. Linking.openURL() opens VeWorld 4. VeWorld processes the request and redirects back via your app's URL scheme 5. VeWorldProvider listens for incoming deep links and dispatches to the appropriate callback
Expo Setup
app.json / app.config.js
Configure your URL scheme in the Expo config:
{
"expo": {
"scheme": "myapp",
"ios": {
"bundleIdentifier": "com.mycompany.myapp",
"infoPlist": {
"CFBundleURLTypes": [
{
"CFBundleURLSchemes": ["myapp"]
}
]
}
},
"android": {
"package": "com.mycompany.myapp",
"intentFilters": [
{
"action": "VIEW",
"data": [{ "scheme": "myapp" }],
"category": ["DEFAULT", "BROWSABLE"]
}
]
}
}
}Expo Router deep link handling
For Expo Router apps, create app/+native-intent.tsx to handle incoming deep links:
// app/+native-intent.tsx
import { type NativeIntent } from 'expo-router';
import { isVeWorldResponse } from '@vechain/react-native-wallet-link';
export function redirectSystemPath({ path }: { path: string }): NativeIntent | string {
// Let VeWorld responses pass through to VeWorldProvider
if (isVeWorldResponse(path)) {
return path;
}
// Handle other deep links normally
return path;
}VeWorldProvider redirectUrl
For Expo projects, install expo-linking and use createURL() to generate the redirect URL. This ensures the correct URL is produced across Expo Go, dev clients, and production builds:
npx expo install expo-linkingimport { createURL } from 'expo-linking';
const redirectUrl = createURL('/');
<VeWorldProvider
redirectUrl={redirectUrl}
// ... other props
>For bare React Native projects (without Expo), use a hardcoded scheme:
<VeWorldProvider
redirectUrl="myapp://"
// ... other props
>The library appends the operation path automatically (e.g., myapp://connect, myapp://sign-transaction).
Bare React Native — iOS Setup
Info.plist
Add URL types to ios/<AppName>/Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>Universal Links (optional)
For HTTPS universal links, add an associated domains entitlement:
1. In Xcode: Signing & Capabilities → + Associated Domains 2. Add applinks:myapp.com 3. Host an apple-app-site-association file at https://myapp.com/.well-known/apple-app-site-association
Bare React Native — Android Setup
AndroidManifest.xml
Add an intent filter to your main activity in android/app/src/main/AndroidManifest.xml:
<activity
android:name=".MainActivity"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" />
</intent-filter>
</activity>IMPORTANT: Use android:launchMode="singleTask" to ensure deep link callbacks return to the existing app instance instead of creating a new one.Redirect URL Patterns
The library generates redirect URLs by appending the operation type:
| Operation | Redirect path |
|---|---|
| Connect | myapp://connect |
| Disconnect | myapp://disconnect |
| Sign Transaction | myapp://sign-transaction |
| Sign Certificate | myapp://sign-certificate |
| Sign Typed Data | myapp://sign-typed-data |
The VeWorldProvider parses these paths to determine which callback to invoke.
Multiple redirect prefixes
You can configure multiple deep link prefixes when VeWorldProvider supports both custom schemes and universal links:
// The redirectUrl should use your custom scheme
<VeWorldProvider
redirectUrl="myapp://"
// ...
>Debugging deep links
iOS
# Test deep link from terminal
xcrun simctl openurl booted "myapp://connect?data=test"Android
# Test deep link from terminal
adb shell am start -a android.intent.action.VIEW -d "myapp://connect?data=test"Expo
# Test with Expo CLI
npx uri-scheme open "myapp://connect" --ios
npx uri-scheme open "myapp://connect" --androidCommon Issues
| Issue | Cause | Fix |
|---|---|---|
| VeWorld opens but never redirects back | URL scheme not configured | Verify scheme in Info.plist / AndroidManifest.xml / app.json |
| App opens a new instance on redirect | Missing singleTask launch mode | Set android:launchMode="singleTask" on Android |
| Callback not firing | VeWorldProvider not mounted | Ensure provider wraps the entire app above navigation |
crypto.getRandomValues error | Missing polyfill | import 'react-native-get-random-values' at the top of your entry file |
Full Example Integration
A complete walkthrough based on the official example app from vechain/react-native-vechain-wallet-link.
Project Dependencies
{
"dependencies": {
"@vechain/react-native-wallet-link": "^1.0.9",
"@vechain/sdk-core": "^2.0.5",
"@vechain/sdk-network": "^2.0.5",
"@react-native-async-storage/async-storage": "^2.2.0",
"react-native-get-random-values": "^1.11.0",
"events": "^3.3.0",
"zustand": "^5.0.8"
}
}Expo projects also need expo-linking to generate the correct redirect URL:>
```bash
npx expo install expo-linking
```
## Entry Point
Import the random values polyfill **first**:
// index.js import 'react-native-get-random-values'; import { registerRootComponent } from 'expo'; import App from './src/App';
registerRootComponent(App);
## State Management with Zustand
### Wallet session store
Persist keyPair, VeWorld public key, address, and session across app restarts:
// stores/useVeWorldStore.ts import { create } from 'zustand'; import { persist, createJSONStorage } from 'zustand/middleware'; import AsyncStorage from '@react-native-async-storage/async-storage'; import type { KeyPair } from '@vechain/react-native-wallet-link';
type VeWorldStore = { veWorldPublicKey: string | null; keyPair: KeyPair | null; address: string | null; session: string | null; setVeWorldPublicKey: (key: string | null) => void; setKeyPair: (keyPair: KeyPair | null) => void; setAddress: (address: string | null) => void; setSession: (session: string | null) => void; reset: () => void; };
export const useVeWorldStore = create<VeWorldStore>()( persist( (set) => ({ veWorldPublicKey: null, keyPair: null, address: null, session: null, setVeWorldPublicKey: (key) => set({ veWorldPublicKey: key }), setKeyPair: (keyPair) => set({ keyPair }), setAddress: (address) => set({ address }), setSession: (session) => set({ session }), reset: () => set({ veWorldPublicKey: null, keyPair: null, address: null, session: null, }), }), { name: 'veworld-store', storage: createJSONStorage(() => AsyncStorage), } ) );
### Response store (for displaying results)
// stores/useResponseStore.ts import { create } from 'zustand'; import { persist, createJSONStorage } from 'zustand/middleware'; import AsyncStorage from '@react-native-async-storage/async-storage';
type ResponseStore = { response: string | null; setResponse: (response: string | null) => void; reset: () => void; };
export const useResponseStore = create<ResponseStore>()( persist( (set) => ({ response: '', setResponse: (response) => set({ response }), reset: () => set({ response: '' }), }), { name: 'response-store', storage: createJSONStorage(() => AsyncStorage), } ) );
## App Root with VeWorldProvider
// App.tsx import React from 'react'; import { SafeAreaProvider } from 'react-native-safe-area-context'; import { NavigationContainer } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; import { VeWorldProvider, decryptPayload, type OnVeWorldConnectedData, type OnVeWorldSignedTransactionData, type OnVeWorldSignedData, } from '@vechain/react-native-wallet-link'; import { createURL } from 'expo-linking'; // Expo projects only import { useVeWorldStore } from './stores/useVeWorldStore'; import { useResponseStore } from './stores/useResponseStore'; import { Home } from './screens/Home';
const TESTNET_URL = 'https://testnet.vechain.org'; const Stack = createNativeStackNavigator();
export default function App() { const { keyPair, setVeWorldPublicKey, setAddress, setSession, reset: resetVeWorld, } = useVeWorldStore(); const { setResponse } = useResponseStore();
// Expo: use createURL() to generate the correct redirect URL for your scheme. // This handles Expo Go (exp://), dev client, and production builds automatically. // For bare React Native, use a hardcoded scheme instead: "myapp://" const redirectUrl = createURL('/');
return ( <SafeAreaProvider> <VeWorldProvider appName="MyApp" appUrl="https://myapp.com" redirectUrl={redirectUrl} node={TESTNET_URL} config={{ onVeWorldConnected: (response) => { if (!keyPair || !response?.response) return; if ('errorCode' in response.response) { setResponse(response.response.errorMessage); return; } const data = decryptPayload<OnVeWorldConnectedData>( keyPair.secretKey, response.response.publicKey, response.response.nonce, response.response.data ); setVeWorldPublicKey(data.publicKey); setAddress(data.address); setSession(data.session); },
onVeWorldDisconnected: (response) => { if (!response?.response) return; if ('errorCode' in response.response) { setResponse(response.response.errorMessage); return; } resetVeWorld(); },
onVeWorldSentTransaction: (response) => { if (!keyPair || !response?.response) return; if ('errorCode' in response.response) { setResponse(response.response.errorMessage); return; } const data = decryptPayload<OnVeWorldSignedTransactionData>( keyPair.secretKey, response.response.publicKey, response.response.nonce, response.response.data ); setResponse(data.id); },
onVeWorldSignedCertificate: (response) => { if (!keyPair || !response?.response) return; if ('errorCode' in response.response) { setResponse(response.response.errorMessage); return; } const data = decryptPayload<OnVeWorldSignedData>( keyPair.secretKey, response.response.publicKey, response.response.nonce, response.response.data ); setResponse(data.signature); },
onVeWorldSignedTypedData: (response) => { if (!keyPair || !response?.response) return; if ('errorCode' in response.response) { setResponse(response.response.errorMessage); return; } const data = decryptPayload<OnVeWorldSignedData>( keyPair.secretKey, response.response.publicKey, response.response.nonce, response.response.data ); setResponse(data.signature); }, }} > <NavigationContainer> <Stack.Navigator> <Stack.Screen name="Home" component={Home} /> </Stack.Navigator> </NavigationContainer> </VeWorldProvider> </SafeAreaProvider> ); }
## Home Screen — Using the Hook
// screens/Home.tsx import React, { useEffect } from 'react'; import { View, Button, Text, StyleSheet, ScrollView } from 'react-native'; import { useVeWorldWallet } from '@vechain/react-native-wallet-link'; import { Address, Clause, VET, type TransactionClause } from '@vechain/sdk-core'; import { encodeBase64 } from 'tweetnacl-util'; import { useVeWorldStore } from '../stores/useVeWorldStore'; import { useResponseStore } from '../stores/useResponseStore';
export function Home() { const { generateKeyPair, connect, disconnect, signAndSendTransaction, signCertificate, signTypedData, } = useVeWorldWallet();
const { keyPair, veWorldPublicKey, address, session, setKeyPair, reset: resetVeWorld, } = useVeWorldStore();
const { response, reset: resetResponse } = useResponseStore();
// Generate key pair on first mount useEffect(() => { if (!keyPair) { const kp = generateKeyPair(); setKeyPair({ secretKey: encodeBase64(kp.secretKey), publicKey: encodeBase64(kp.publicKey), }); } }, [keyPair, generateKeyPair, setKeyPair]);
const isConnected = !!address && !!session;
const handleConnect = () => { if (!keyPair) return; resetResponse(); connect(keyPair.publicKey); };
const handleDisconnect = () => { if (!keyPair || !veWorldPublicKey || !session) return; resetResponse(); disconnect(keyPair, veWorldPublicKey, session); };
const handleSendVET = () => { if (!keyPair || !veWorldPublicKey || !session) return; resetResponse();
const clauses: TransactionClause[] = [ Clause.transferVET( Address.of('0x9199828f14cf883c8d311245bec34ec0b51fedcb'), VET.of(0.1) ) as TransactionClause, ];
signAndSendTransaction( keyPair, veWorldPublicKey, session, clauses, 'Send 0.1 VET' ); };
const handleSignCertificate = () => { if (!keyPair || !veWorldPublicKey || !session) return; resetResponse();
signCertificate(keyPair, veWorldPublicKey, session, { purpose: 'identification', payload: { type: 'text', content: 'Hello, world!' }, }); };
const handleSignTypedData = () => { if (!keyPair || !veWorldPublicKey || !session) return; resetResponse();
signTypedData(keyPair, veWorldPublicKey, session, { domain: { name: 'My DApp', version: '1.0.0', chainId: 1 }, origin: 'https://myapp.com', types: { Person: [ { name: 'name', type: 'string' }, { name: 'wallet', type: 'address' }, ], }, value: { name: 'John Doe', wallet: '0x9199828f14cf883c8d311245bec34ec0b51fedcb', }, }); };
return ( <ScrollView contentContainerStyle={styles.container}> <Text style={styles.status}> {isConnected ? Connected: ${address} : 'Not connected'} </Text>
{!isConnected ? ( <Button title="Connect to VeWorld" onPress={handleConnect} /> ) : ( <> <Button title="Disconnect" onPress={handleDisconnect} />
<Text style={styles.section}>Message Signing</Text> <Button title="Sign Certificate" onPress={handleSignCertificate} /> <Button title="Sign Typed Data" onPress={handleSignTypedData} />
<Text style={styles.section}>Transactions</Text> <Button title="Send 0.1 VET" onPress={handleSendVET} /> </> )}
{response ? ( <Text style={styles.response}>Response: {response}</Text> ) : null} </ScrollView> ); }
const styles = StyleSheet.create({ container: { padding: 20, gap: 12 }, status: { fontSize: 16, fontWeight: 'bold', marginBottom: 8 }, section: { fontSize: 14, fontWeight: '600', marginTop: 16 }, response: { fontSize: 12, marginTop: 16, color: '#666' }, });
## Key Implementation Patterns
### 1. Always check errors before decrypting
Every callback must guard against error responses:
if ('errorCode' in response.response) { // Handle error — do NOT attempt decryption return; }
### 2. Persist session state
The keyPair, veWorldPublicKey, address, and session must survive app restarts. Use AsyncStorage with Zustand persist, MMKV, or any persistent store.
### 3. Generate key pair once
Generate a single key pair and reuse it for the lifetime of the session. Only generate a new one if the user explicitly resets.
### 4. Clean up on disconnect
When `onVeWorldDisconnected` fires, clear all stored wallet state (keyPair can optionally be preserved for reconnection).
### 5. Multi-clause transactions
Use `@vechain/sdk-core` `Clause` helpers to build transaction clauses:
import { Clause, Address, VET, coder, type TransactionClause } from '@vechain/sdk-core';
// VET transfer Clause.transferVET(Address.of(recipient), VET.of(amount))
// VTHO transfer (or any VIP-180 token) const transferABI = coder.createInterface(['function transfer(address to, uint256 amount)']); { to: VTHO_CONTRACT_ADDRESS, value: '0x0', data: transferABI.encodeFunctionData('transfer', [recipient, amount]), }
// Multiple clauses in one transaction signAndSendTransaction(keyPair, veWorldPublicKey, session, [clause1, clause2, clause3]);
@vechain/react-native-wallet-link — API Reference
Installation
npm install @vechain/react-native-wallet-link
# Peer dependencies (required):
npm install @vechain/sdk-core @vechain/sdk-network react-native-get-random-values eventsCurrent version: 1.0.9
Runtime dependencies (bundled): tweetnacl, tweetnacl-util
IMPORTANT: Importreact-native-get-random-valuesat the top of your entry file (before any NaCl usage) to polyfillcrypto.getRandomValuesin React Native.
Exports
// Components
export { VeWorldProvider } from './components/VeWorldProvider';
// Hooks
export { useVeWorldWallet } from './hooks/useVeWorldWallet';
// All types
export * from './types';
// Utilities
export {
decryptPayload,
encryptPayload,
processResponse,
isVeWorldResponse,
LinkEvent,
} from './utils';VeWorldProvider
Wrap your app root with this provider. It sets up deep link listeners and dispatches wallet events.
import { VeWorldProvider } from '@vechain/react-native-wallet-link';
<VeWorldProvider
appName="MyApp"
appUrl="https://myapp.com"
redirectUrl="myapp://"
node="https://testnet.vechain.org"
config={{
onVeWorldConnected: (response) => { /* handle connection */ },
onVeWorldDisconnected: (response) => { /* handle disconnection */ },
onVeWorldSentTransaction: (response) => { /* handle tx result */ },
onVeWorldSignedCertificate: (response) => { /* handle certificate */ },
onVeWorldSignedTypedData: (response) => { /* handle typed data */ },
}}
>
{children}
</VeWorldProvider>Props
| Prop | Type | Description |
|---|---|---|
appName | string | Application display name shown in VeWorld |
appUrl | string | Application URL identifier |
redirectUrl | string | Deep link redirect URI (e.g., myapp://) |
node | string | VeChain node endpoint URL |
config | VeWorldConfig | Event handler callbacks (see below) |
VeWorldConfig callbacks
Each callback receives OnVeWorldResponseWithEvent:
type OnVeWorldResponseWithEvent = {
event: LinkEvent;
response: OnVeWorldResponse | OnVeWorldError | undefined;
};
type OnVeWorldResponse = {
data: string; // encrypted payload
nonce: string; // decryption nonce
publicKey: string;
};
type OnVeWorldError = {
errorCode: string;
errorMessage: string;
};Always check for errors before decrypting:
onVeWorldConnected: (response) => {
if (!response?.response) return;
// Check for error
if ('errorCode' in response.response) {
console.error(response.response.errorMessage);
return;
}
// Decrypt successful response
const data = decryptPayload<OnVeWorldConnectedData>(
keyPair.secretKey,
response.response.publicKey,
response.response.nonce,
response.response.data
);
// data = { publicKey, address, session }
}Context value
The provider exposes via VeWorldContext:
appName,appUrl,redirectUrl— from propsthor—ThorClientinstance connected to the configured node
useVeWorldWallet Hook
Access all wallet operations. Must be used within VeWorldProvider.
import { useVeWorldWallet } from '@vechain/react-native-wallet-link';
const {
generateKeyPair,
connect,
disconnect,
signAndSendTransaction,
signCertificate,
signTypedData,
} = useVeWorldWallet();generateKeyPair
Creates a NaCl box key pair for encrypted communication with VeWorld.
const generateKeyPair: () => nacl.BoxKeyPair;
// Returns { secretKey: Uint8Array, publicKey: Uint8Array }Encode for storage:
import { encodeBase64 } from 'tweetnacl-util';
const kp = generateKeyPair();
const keyPair = {
secretKey: encodeBase64(kp.secretKey),
publicKey: encodeBase64(kp.publicKey),
};
// Store keyPair persistently (AsyncStorage, MMKV, etc.)connect
Initiates wallet connection by opening VeWorld via deep link.
const connect: (publicKey: string) => Promise<void>;publicKey— Base64-encoded public key fromgenerateKeyPair- Automatically fetches genesis block ID from the configured node
- Opens VeWorld with connection parameters
- Response arrives in
onVeWorldConnectedcallback
Response data (after decryption):
type OnVeWorldConnectedData = {
publicKey: string; // VeWorld's public key for future encryption
address: string; // Connected wallet address
session: string; // Session token for authenticated requests
};disconnect
Ends the wallet session.
const disconnect: (
keyPair: KeyPair,
veWorldPublicKey: string,
session: string,
description?: string
) => Promise<void>;signAndSendTransaction
Signs and broadcasts a transaction via VeWorld. Supports multi-clause transactions.
const signAndSendTransaction: (
keyPair: KeyPair,
veWorldPublicKey: string,
session: string,
transaction: TransactionClause[],
description?: string
) => Promise<null>;Response data (after decryption in onVeWorldSentTransaction):
type OnVeWorldSignedTransactionData = {
id: string; // Transaction ID
transaction: Transaction; // Full transaction object
};Example — send VET:
import { Address, Clause, VET, type TransactionClause } from '@vechain/sdk-core';
const clauses: TransactionClause[] = [
Clause.transferVET(
Address.of('0x9199828f14cf883c8d311245bec34ec0b51fedcb'),
VET.of(0.1)
) as TransactionClause,
];
await signAndSendTransaction(keyPair, veWorldPublicKey, session, clauses, 'Send 0.1 VET');signCertificate
Signs a certificate message (identification, verification, or attestation).
const signCertificate: (
keyPair: KeyPair,
veWorldPublicKey: string,
session: string,
certificate: CertificateMessage,
description?: string
) => Promise<void>;CertificateMessage type:
type CertificateMessage = {
purpose: 'identification' | 'verification' | 'attestation';
payload: {
type: string;
content: string;
};
domain?: string;
timestamp?: number;
};Response data (after decryption in onVeWorldSignedCertificate):
type OnVeWorldSignedData = {
signature: string;
annex?: {
domain: string;
timestamp: number;
signer: string;
};
};signTypedData
Signs EIP-712 typed data.
const signTypedData: (
keyPair: KeyPair,
veWorldPublicKey: string,
session: string,
typedData: TypedDataBody,
description?: string
) => Promise<void>;TypedDataBody type:
type TypedDataBody = {
domain: ethers.TypedDataDomain;
origin: string;
types: Record<string, ethers.TypedDataField[]>;
value: Record<string, unknown>;
};KeyPair Type
All signing methods require a KeyPair with Base64-encoded keys:
type KeyPair = {
secretKey: string; // Base64-encoded NaCl secret key
publicKey: string; // Base64-encoded NaCl public key
};Utility Functions
decryptPayload
Decrypt an encrypted response from VeWorld.
function decryptPayload<T>(
secretKey: string, // Base64 secret key
veWorldPublicKey: string, // Base64 VeWorld public key (from response)
nonce: string, // Base64 nonce (from response)
payload: string // Base64 encrypted data (from response)
): T;encryptPayload
Encrypt a payload to send to VeWorld (used internally by the hook).
function encryptPayload(
secretKey: string,
veWorldPublicKey: string,
payload: string
): [string, string]; // [nonce, encryptedPayload] both Base64isVeWorldResponse
Check if a deep link path is a VeWorld callback event.
function isVeWorldResponse(path: string): boolean;processResponse
Parse a deep link URL into a structured response.
function processResponse(url: string): Promise<OnVeWorldResponseWithEvent>;LinkEvent Enum
enum LinkEvent {
Connect = 'connect',
Disconnect = 'disconnect',
SignTransaction = 'sign-transaction',
SignCertificate = 'sign-certificate',
SignTypedData = 'sign-typed-data',
}Network Configuration
Pass the appropriate node URL to VeWorldProvider:
| Network | Node URL |
|---|---|
| Mainnet | https://mainnet.vechain.org |
| Testnet | https://testnet.vechain.org |
| Solo | http://localhost:8669 (or custom) |
Additional Types
type VeWorldNetwork = 'mainnet' | 'testnet' | 'solo';
type TransactionMethod =
| 'thor_sendTransaction'
| 'thor_signCertificate'
| 'thor_signTypedData';
type TransactionMessage = TransactionClause & {
comment?: string;
abi?: object;
};
type ErrorResponse = {
error_code: string;
error_message: string;
};