@veridex/sdk 1.0.0-beta.9 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/LICENSE +170 -21
  2. package/README.md +574 -117
  3. package/dist/EVMClient-DtqvdfUP.d.mts +376 -0
  4. package/dist/auth/prepareAuth.d.mts +25 -0
  5. package/dist/auth/prepareAuth.js +2406 -0
  6. package/dist/auth/prepareAuth.js.map +1 -0
  7. package/dist/auth/prepareAuth.mjs +151 -0
  8. package/dist/auth/prepareAuth.mjs.map +1 -0
  9. package/dist/chains/aptos/index.d.mts +6 -5
  10. package/dist/chains/aptos/index.js +66 -39
  11. package/dist/chains/aptos/index.js.map +1 -1
  12. package/dist/chains/aptos/index.mjs +5 -547
  13. package/dist/chains/aptos/index.mjs.map +1 -1
  14. package/dist/chains/avalanche/index.d.mts +137 -0
  15. package/dist/chains/avalanche/index.js +1555 -0
  16. package/dist/chains/avalanche/index.js.map +1 -0
  17. package/dist/chains/avalanche/index.mjs +10 -0
  18. package/dist/chains/avalanche/index.mjs.map +1 -0
  19. package/dist/chains/evm/index.d.mts +5 -3
  20. package/dist/chains/evm/index.js +165 -3
  21. package/dist/chains/evm/index.js.map +1 -1
  22. package/dist/chains/evm/index.mjs +8 -1200
  23. package/dist/chains/evm/index.mjs.map +1 -1
  24. package/dist/chains/solana/index.d.mts +1 -1
  25. package/dist/chains/solana/index.js.map +1 -1
  26. package/dist/chains/solana/index.mjs +4 -486
  27. package/dist/chains/solana/index.mjs.map +1 -1
  28. package/dist/chains/stacks/index.d.mts +559 -0
  29. package/dist/chains/stacks/index.js +1207 -0
  30. package/dist/chains/stacks/index.js.map +1 -0
  31. package/dist/chains/stacks/index.mjs +71 -0
  32. package/dist/chains/stacks/index.mjs.map +1 -0
  33. package/dist/chains/starknet/index.d.mts +4 -5
  34. package/dist/chains/starknet/index.js +1 -13
  35. package/dist/chains/starknet/index.js.map +1 -1
  36. package/dist/chains/starknet/index.mjs +5 -503
  37. package/dist/chains/starknet/index.mjs.map +1 -1
  38. package/dist/chains/sui/index.d.mts +4 -4
  39. package/dist/chains/sui/index.js +2 -2
  40. package/dist/chains/sui/index.js.map +1 -1
  41. package/dist/chains/sui/index.mjs +5 -529
  42. package/dist/chains/sui/index.mjs.map +1 -1
  43. package/dist/chunk-5T6KPH7A.mjs +1082 -0
  44. package/dist/chunk-5T6KPH7A.mjs.map +1 -0
  45. package/dist/chunk-72ZA3OYQ.mjs +20 -0
  46. package/dist/chunk-72ZA3OYQ.mjs.map +1 -0
  47. package/dist/chunk-F3YAGZSW.mjs +269 -0
  48. package/dist/chunk-F3YAGZSW.mjs.map +1 -0
  49. package/dist/chunk-GWJRKDSA.mjs +549 -0
  50. package/dist/chunk-GWJRKDSA.mjs.map +1 -0
  51. package/dist/chunk-M3MM4YMF.mjs +417 -0
  52. package/dist/chunk-M3MM4YMF.mjs.map +1 -0
  53. package/dist/chunk-MLXQHIH2.mjs +426 -0
  54. package/dist/chunk-MLXQHIH2.mjs.map +1 -0
  55. package/dist/chunk-N4A2RMUN.mjs +216 -0
  56. package/dist/chunk-N4A2RMUN.mjs.map +1 -0
  57. package/dist/chunk-NUWSMJFJ.mjs +179 -0
  58. package/dist/chunk-NUWSMJFJ.mjs.map +1 -0
  59. package/dist/chunk-OVMMTL6H.mjs +330 -0
  60. package/dist/chunk-OVMMTL6H.mjs.map +1 -0
  61. package/dist/chunk-PDHZ5X5O.mjs +565 -0
  62. package/dist/chunk-PDHZ5X5O.mjs.map +1 -0
  63. package/dist/chunk-Q5O3M5LP.mjs +422 -0
  64. package/dist/chunk-Q5O3M5LP.mjs.map +1 -0
  65. package/dist/chunk-QDO6NQ7P.mjs +840 -0
  66. package/dist/chunk-QDO6NQ7P.mjs.map +1 -0
  67. package/dist/chunk-QT4ZZ4GM.mjs +509 -0
  68. package/dist/chunk-QT4ZZ4GM.mjs.map +1 -0
  69. package/dist/chunk-SXXGTQIR.mjs +464 -0
  70. package/dist/chunk-SXXGTQIR.mjs.map +1 -0
  71. package/dist/chunk-USDA5JTN.mjs +1249 -0
  72. package/dist/chunk-USDA5JTN.mjs.map +1 -0
  73. package/dist/chunk-V636MIV3.mjs +52 -0
  74. package/dist/chunk-V636MIV3.mjs.map +1 -0
  75. package/dist/chunk-X7BZMSPQ.mjs +407 -0
  76. package/dist/chunk-X7BZMSPQ.mjs.map +1 -0
  77. package/dist/chunk-YCUJZ6Z7.mjs +829 -0
  78. package/dist/chunk-YCUJZ6Z7.mjs.map +1 -0
  79. package/dist/constants.d.mts +1 -1
  80. package/dist/constants.js +26 -12
  81. package/dist/constants.js.map +1 -1
  82. package/dist/constants.mjs +16 -375
  83. package/dist/constants.mjs.map +1 -1
  84. package/dist/index-DDalBhAm.d.mts +243 -0
  85. package/dist/index.d.mts +2511 -556
  86. package/dist/index.js +15216 -10262
  87. package/dist/index.js.map +1 -1
  88. package/dist/index.mjs +4125 -7839
  89. package/dist/index.mjs.map +1 -1
  90. package/dist/passkey.d.mts +182 -0
  91. package/dist/passkey.js +914 -0
  92. package/dist/passkey.js.map +1 -0
  93. package/dist/passkey.mjs +15 -0
  94. package/dist/passkey.mjs.map +1 -0
  95. package/dist/payload.js.map +1 -1
  96. package/dist/payload.mjs +25 -244
  97. package/dist/payload.mjs.map +1 -1
  98. package/dist/portfolio-V347KZOL.mjs +13 -0
  99. package/dist/portfolio-V347KZOL.mjs.map +1 -0
  100. package/dist/queries/index.js +145 -12
  101. package/dist/queries/index.js.map +1 -1
  102. package/dist/queries/index.mjs +14 -1496
  103. package/dist/queries/index.mjs.map +1 -1
  104. package/dist/{types-FJL7j6gQ.d.ts → types-B7V5VNbO.d.mts} +6 -2
  105. package/dist/{types-ChIsqCiw.d.mts → types-DP2CQT8p.d.mts} +12 -1
  106. package/dist/types.d.mts +16 -0
  107. package/dist/types.js.map +1 -1
  108. package/dist/utils.js +25 -11
  109. package/dist/utils.js.map +1 -1
  110. package/dist/utils.mjs +19 -371
  111. package/dist/utils.mjs.map +1 -1
  112. package/dist/wormhole.js.map +1 -1
  113. package/dist/wormhole.mjs +25 -397
  114. package/dist/wormhole.mjs.map +1 -1
  115. package/package.json +28 -3
  116. package/scripts/patch-noble-curves.js +78 -0
  117. package/dist/chains/aptos/index.d.ts +0 -145
  118. package/dist/chains/evm/index.d.ts +0 -5
  119. package/dist/chains/solana/index.d.ts +0 -116
  120. package/dist/chains/starknet/index.d.ts +0 -172
  121. package/dist/chains/sui/index.d.ts +0 -182
  122. package/dist/constants.d.ts +0 -150
  123. package/dist/index-0NXfbk0z.d.ts +0 -637
  124. package/dist/index-D0dLVjTA.d.mts +0 -637
  125. package/dist/index.d.ts +0 -3123
  126. package/dist/payload.d.ts +0 -125
  127. package/dist/queries/index.d.ts +0 -148
  128. package/dist/types-ChIsqCiw.d.ts +0 -565
  129. package/dist/types-FJL7j6gQ.d.mts +0 -172
  130. package/dist/types.d.ts +0 -407
  131. package/dist/utils.d.ts +0 -81
  132. package/dist/wormhole.d.ts +0 -167
package/README.md CHANGED
@@ -3,213 +3,670 @@
3
3
  [![npm version](https://img.shields.io/npm/v/@veridex/sdk.svg)](https://www.npmjs.com/package/@veridex/sdk)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
 
6
- Veridex Protocol SDK - Client library for **Passkey-based cross-chain authentication**.
6
+ **Passkey-based cross-chain identity and authentication.** One passkey. Every chain.
7
7
 
8
- Build applications with WebAuthn/Passkeys (P-256) that work across EVM, Solana, Aptos, Sui, and Starknet.
9
-
10
- ## Features
11
-
12
- - **Passkey Authentication** - WebAuthn P-256 signature verification (no seed phrases)
13
- - **Cross-Chain Support** - EVM, Solana, Aptos, Sui, Starknet
14
- - **Deterministic Vaults** - Same address across all EVM chains
15
- - **Gasless Transactions** - Relayer-sponsored execution
16
- - **Session Keys** - Temporary delegated access for smooth UX
17
- - **Wormhole Integration** - Guardian-attested cross-chain messaging
18
-
19
- ## Installation
8
+ Register a WebAuthn passkey once, get a deterministic vault address on every supported chain. No seed phrases, no private keys, no browser extensions.
20
9
 
21
10
  ```bash
22
11
  npm install @veridex/sdk ethers
23
- # or
24
- yarn add @veridex/sdk ethers
25
- # or
26
- bun add @veridex/sdk ethers
27
12
  ```
28
13
 
29
- ## Quick Start
30
-
31
14
  ```typescript
32
15
  import { createSDK } from '@veridex/sdk';
33
16
 
34
- // Initialize SDK (testnet by default)
17
+ // Initialize returns synchronously, defaults to testnet
35
18
  const sdk = createSDK('base');
36
19
 
37
- // Register a passkey
20
+ // Register a passkey (biometric prompt)
38
21
  const credential = await sdk.passkey.register('user@example.com', 'My Wallet');
39
22
 
40
- // Get your vault address (same on all EVM chains!)
41
- const vaultAddress = sdk.getVaultAddress();
42
- console.log('Your vault:', vaultAddress);
23
+ // Deterministic vault address derived from your passkey
24
+ const vault = sdk.getVaultAddress();
25
+ console.log('Your vault:', vault);
43
26
 
44
- // Transfer tokens
45
- await sdk.transfer({
27
+ // Prepare and execute a transfer (requires a signer to pay gas)
28
+ const prepared = await sdk.prepareTransfer({
29
+ targetChain: 10004, // Base Sepolia Wormhole chain ID
46
30
  token: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // USDC
47
31
  recipient: '0x742d35Cc6634C0532925a3b844Bc9e7595f5A234',
48
- amount: 1000000n, // 1 USDC (6 decimals)
32
+ amount: 1000000n, // 1 USDC (6 decimals)
49
33
  });
34
+ const result = await sdk.executeTransfer(prepared, signer);
35
+ console.log('Tx hash:', result.transactionHash);
50
36
  ```
51
37
 
52
- ## Networks
38
+ ## Architecture
39
+
40
+ ```
41
+ ┌─────────────────────┐
42
+ │ WebAuthn Passkey │
43
+ │ (P-256 / secp256r1)│
44
+ └──────────┬──────────┘
45
+
46
+ ┌──────────▼──────────┐
47
+ │ Veridex Hub │
48
+ │ (Base / EVM) │
49
+ │ Identity + Vaults │
50
+ └──────────┬──────────┘
51
+ │ Wormhole / Custom Bridge
52
+ ┌────────┬───────────┼───────────┬────────┬────────┐
53
+ ▼ ▼ ▼ ▼ ▼ ▼
54
+ Solana Aptos Sui Starknet Stacks EVM Spokes
55
+ (Ed25519) (Ed25519) (secp256k1) (Stark) (secp256r1) (Opt/Arb/Poly)
56
+ ```
57
+
58
+ **Hub-and-Spoke model**: Identity lives on the Hub (Base). Actions are dispatched to spoke chains via Wormhole guardian-attested messages or custom bridge attestations.
59
+
60
+ ## Supported Chains
61
+
62
+ | Chain | Type | Wormhole ID | Signature | Networks |
63
+ |-------|------|-------------|-----------|----------|
64
+ | **Base** | Hub (EVM) | 30 | secp256r1 (passkey) + secp256k1 (session) | Sepolia + Mainnet |
65
+ | **Ethereum** | Spoke (EVM) | 2 | secp256r1 + secp256k1 | Sepolia + Mainnet |
66
+ | **Optimism** | Spoke (EVM) | 24 | secp256r1 + secp256k1 | Sepolia + Mainnet |
67
+ | **Arbitrum** | Spoke (EVM) | 23 | secp256r1 + secp256k1 | Sepolia + Mainnet |
68
+ | **Polygon** | Spoke (EVM) | 5 | secp256r1 + secp256k1 | Amoy + Mainnet |
69
+ | **Monad** | Spoke (EVM) | 10048 | secp256r1 (EIP-7951) + secp256k1 | Testnet + Mainnet |
70
+ | **Solana** | Spoke | 1 | Ed25519 | Devnet + Mainnet |
71
+ | **Aptos** | Spoke | 22 | Ed25519 | Testnet + Mainnet |
72
+ | **Sui** | Spoke | 21 | secp256k1 | Testnet + Mainnet |
73
+ | **Starknet** | Spoke | 50001 | Stark ECDSA | Sepolia + Mainnet |
74
+ | **Stacks** | Spoke | 60 | secp256r1 (native!) + secp256k1 | Testnet + Mainnet |
75
+
76
+ ## Key Features
77
+
78
+ ### Passkey Registration & Authentication
53
79
 
54
80
  ```typescript
55
- // Testnet (default)
56
- const testnetSdk = createSDK('base');
81
+ import { createSDK } from '@veridex/sdk';
57
82
 
58
- // Mainnet
59
- const mainnetSdk = createSDK('base', { network: 'mainnet' });
83
+ const sdk = createSDK('base');
60
84
 
61
- // Custom RPC
62
- const customSdk = createSDK('base', {
63
- rpcUrl: 'https://my-rpc.example.com'
64
- });
85
+ // Register — triggers biometric prompt, returns credential
86
+ const credential = await sdk.passkey.register('user@example.com', 'My Wallet');
87
+ console.log('Key hash:', credential.keyHash);
88
+ console.log('Credential ID:', credential.credentialId);
89
+
90
+ // Check for existing passkeys
91
+ const stored = sdk.passkey.getAllStoredCredentials();
92
+ if (stored.length > 0) {
93
+ // Authenticate with a discoverable credential (shows passkey picker)
94
+ const { credential, signature } = await sdk.passkey.authenticate();
95
+ console.log('Authenticated as:', credential.keyHash);
96
+ } else {
97
+ // Or set a known credential directly
98
+ sdk.passkey.setCredential({
99
+ credentialId: 'abc123',
100
+ publicKeyX: BigInt('0x...'),
101
+ publicKeyY: BigInt('0x...'),
102
+ keyHash: '0x...',
103
+ });
104
+ }
65
105
  ```
66
106
 
67
- ## Supported Chains
107
+ - **RIP-7212** native P-256 verification on EVM (~3,450 gas)
108
+ - **FCL fallback** for chains without precompile
109
+ - **Stacks** has native `secp256r1-verify` in Clarity — no workarounds needed
110
+ - **Monad** has EIP-7951 P-256 precompile at `0x0100` (6,900 gas)
68
111
 
69
- | Chain | Type | Status |
70
- |-------|------|--------|
71
- | Base | Hub (EVM) | Testnet + Mainnet |
72
- | Optimism | Spoke (EVM) | Testnet + Mainnet |
73
- | Arbitrum | Spoke (EVM) | Testnet + Mainnet |
74
- | Ethereum | Spoke (EVM) | Testnet + Mainnet |
75
- | Polygon | Spoke (EVM) | Testnet + Mainnet |
76
- | Solana | Spoke | Devnet + Mainnet |
77
- | Aptos | Spoke | Testnet + Mainnet |
78
- | Sui | Spoke | Testnet + Mainnet |
79
- | Starknet | Spoke | Sepolia + Mainnet |
112
+ ### Deterministic Vaults
80
113
 
81
- ## Gasless Transactions
114
+ ```typescript
115
+ // Same address on Base, Optimism, Arbitrum, Ethereum, Polygon
116
+ const vault = sdk.getVaultAddress();
117
+
118
+ // Get vault address for a specific chain
119
+ const opVault = sdk.getVaultAddressForChain(24); // Optimism
120
+
121
+ // Check if vault exists on-chain
122
+ const info = await sdk.getVaultInfo();
123
+ console.log('Deployed:', info?.exists);
124
+
125
+ // Create vault (user pays gas)
126
+ const result = await sdk.createVault(signer);
127
+ console.log('Vault created:', result.address);
128
+
129
+ // Or create with sponsored gas (Veridex pays)
130
+ const sponsored = await sdk.createVaultSponsored();
131
+ ```
132
+
133
+ ### Transfers
134
+
135
+ ```typescript
136
+ import { createSDK } from '@veridex/sdk';
137
+ import { ethers } from 'ethers';
138
+
139
+ const sdk = createSDK('base', { network: 'testnet' });
140
+
141
+ // After registering or setting a credential...
142
+ await sdk.passkey.register('user@example.com', 'My Wallet');
143
+
144
+ // 1. Prepare transfer (shows gas estimate before signing)
145
+ const prepared = await sdk.prepareTransfer({
146
+ targetChain: 10004, // Base Sepolia
147
+ token: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // USDC
148
+ recipient: '0x742d35Cc6634C0532925a3b844Bc9e7595f5A234',
149
+ amount: 1000000n, // 1 USDC
150
+ });
151
+
152
+ // 2. Show human-readable summary
153
+ const summary = await sdk.getTransactionSummary(prepared);
154
+ console.log(summary.title); // "Transfer"
155
+ console.log(summary.description); // "Send 1.0 USDC to 0x742d...5A234"
156
+ console.log('Gas cost:', prepared.formattedCost);
157
+
158
+ // 3. Execute (signs with passkey, then dispatches)
159
+ const provider = new ethers.JsonRpcProvider('https://sepolia.base.org');
160
+ const signer = new ethers.Wallet(PRIVATE_KEY, provider);
161
+ const result = await sdk.executeTransfer(prepared, signer);
162
+ console.log('Tx hash:', result.transactionHash);
163
+
164
+ // 4. Wait for confirmation
165
+ const state = await sdk.waitForTransaction(result.transactionHash);
166
+ console.log('Confirmed in block:', state.blockNumber);
167
+ ```
168
+
169
+ ### Gasless Transfers (via Relayer)
82
170
 
83
171
  ```typescript
84
172
  const sdk = createSDK('base', {
85
- relayerUrl: 'https://relayer.veridex.io',
173
+ network: 'testnet',
174
+ relayerUrl: 'https://relayer.veridex.network',
86
175
  relayerApiKey: 'your-api-key',
87
176
  });
88
177
 
89
- // Transfers are now gasless
90
- await sdk.transferViaRelayer({
91
- token: USDC_ADDRESS,
92
- recipient: '0x...',
178
+ await sdk.passkey.register('user@example.com', 'My Wallet');
179
+
180
+ // Relayer sponsors gas — user pays nothing
181
+ const result = await sdk.transferViaRelayer({
182
+ targetChain: 10004,
183
+ token: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
184
+ recipient: '0x742d35Cc6634C0532925a3b844Bc9e7595f5A234',
93
185
  amount: 1000000n,
94
186
  });
187
+ console.log('Tx hash:', result.transactionHash);
95
188
  ```
96
189
 
97
- ## Session Keys
190
+ ### Session Keys
98
191
 
99
- Enable seamless UX without repeated biometric prompts:
192
+ Session keys are managed via the `SessionManager` class, separate from the main SDK:
100
193
 
101
194
  ```typescript
102
- // Create a 1-hour session with 0.1 ETH limit
103
- const session = await sdk.sessions.create({
104
- duration: 3600,
105
- maxValue: parseEther('0.1'),
195
+ import { createSDK, SessionManager } from '@veridex/sdk';
196
+
197
+ const sdk = createSDK('base');
198
+ await sdk.passkey.register('user@example.com', 'My Wallet');
199
+
200
+ // SessionManager wraps the SDK for session operations
201
+ const sessionManager = new SessionManager({ sdk });
202
+
203
+ // Create a session (one passkey auth)
204
+ const session = await sessionManager.createSession({
205
+ duration: 3600, // 1 hour
206
+ maxValue: BigInt(1e18), // Max 1 token per tx
207
+ allowedChains: [10004], // Base Sepolia only
106
208
  });
107
209
 
108
- // Execute multiple transactions without prompts
109
- await sdk.sessions.transfer(session, { ... });
110
- await sdk.sessions.transfer(session, { ... });
210
+ // Execute transactions with session key (no biometric prompts)
211
+ await sessionManager.executeWithSession({
212
+ targetChain: 10004,
213
+ token: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
214
+ recipient: '0x...',
215
+ amount: 1000000n,
216
+ }, session);
111
217
 
112
- // Revoke when done
113
- await sdk.sessions.revoke(session);
218
+ // Revoke anytime
219
+ await sessionManager.revokeSession(session);
114
220
  ```
115
221
 
116
- ## Cross-Chain Bridging
222
+ ### Session Key Cryptography (Low-Level)
117
223
 
118
224
  ```typescript
119
- import { parseUnits } from 'ethers';
225
+ import {
226
+ generateSecp256k1KeyPair,
227
+ computeSessionKeyHash,
228
+ deriveEncryptionKey,
229
+ encrypt,
230
+ decrypt,
231
+ } from '@veridex/sdk';
232
+
233
+ // Generate a session key pair
234
+ const keyPair = generateSecp256k1KeyPair();
235
+ console.log('Public key:', keyPair.publicKey);
120
236
 
121
- await sdk.bridge({
122
- targetChain: 'optimism',
123
- token: USDC_ADDRESS,
124
- amount: parseUnits('100', 6),
125
- recipient: '0x...', // Optional, defaults to your vault
237
+ // Compute on-chain key hash
238
+ const keyHash = computeSessionKeyHash(keyPair.publicKey);
239
+
240
+ // Encrypt private key (only passkey owner can decrypt)
241
+ const encryptionKey = await deriveEncryptionKey(credential.credentialId);
242
+ const encrypted = await encrypt(keyPair.privateKey, encryptionKey);
243
+ const decrypted = await decrypt(encrypted, encryptionKey);
244
+ ```
245
+
246
+ ### Cross-Chain Bridging
247
+
248
+ ```typescript
249
+ const sdk = createSDK('base', { network: 'testnet' });
250
+ await sdk.passkey.register('user@example.com', 'My Wallet');
251
+
252
+ // Prepare bridge with fee estimation
253
+ const prepared = await sdk.prepareBridge({
254
+ sourceChain: 10004, // Base Sepolia
255
+ destinationChain: 10005, // Optimism Sepolia
256
+ token: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
257
+ amount: 1000000n,
258
+ });
259
+ console.log('Bridge fees:', prepared.fees.formattedTotal);
260
+
261
+ // Execute with progress tracking
262
+ const result = await sdk.executeBridge(prepared, signer, (progress) => {
263
+ console.log(`Step ${progress.step}/${progress.totalSteps}: ${progress.message}`);
264
+ });
265
+ console.log('Source tx:', result.transactionHash);
266
+ console.log('VAA ready:', !!result.vaa);
267
+
268
+ // Or bridge gaslessly via relayer
269
+ const gaslessResult = await sdk.bridgeViaRelayer({
270
+ sourceChain: 10004,
271
+ destinationChain: 10005,
272
+ token: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
273
+ amount: 1000000n,
126
274
  });
127
275
  ```
128
276
 
129
- ## API Reference
277
+ ### Balances
130
278
 
131
- ### Core
279
+ ```typescript
280
+ const sdk = createSDK('base', { network: 'testnet' });
281
+ await sdk.passkey.register('user@example.com', 'My Wallet');
282
+
283
+ // Native token balance
284
+ const native = await sdk.getVaultNativeBalance();
285
+ console.log(`${native.token.symbol}: ${native.formatted}`);
286
+
287
+ // All token balances on current chain
288
+ const portfolio = await sdk.getVaultBalances();
289
+ for (const entry of portfolio.tokens) {
290
+ console.log(`${entry.token.symbol}: ${entry.formatted}`);
291
+ }
292
+ console.log('Total USD:', portfolio.totalUsdValue);
293
+
294
+ // Multi-chain balances
295
+ const multiChain = await sdk.getMultiChainBalances([10004, 10005, 10003]);
296
+ for (const chain of multiChain) {
297
+ console.log(`${chain.chainName}: ${chain.tokens.length} tokens`);
298
+ }
299
+ ```
300
+
301
+ ### Spending Limits
132
302
 
133
- | Export | Description |
134
- |--------|-------------|
135
- | `createSDK(chain, config?)` | Create SDK for a chain |
136
- | `VeridexSDK` | Main SDK class |
137
- | `PasskeyManager` | WebAuthn credential management |
138
- | `WalletManager` | Vault address derivation |
139
- | `SessionManager` | Session key management |
303
+ ```typescript
304
+ import { ethers } from 'ethers';
305
+
306
+ // Check current on-chain spending limits
307
+ const limits = await sdk.getSpendingLimits();
308
+ console.log('Daily remaining:', limits.dailyRemaining);
309
+
310
+ // Check if a specific amount is allowed
311
+ const check = await sdk.checkSpendingLimit(ethers.parseEther('1.0'));
312
+ if (!check.allowed) {
313
+ console.log('Blocked:', check.message);
314
+ console.log('Suggestions:', check.suggestions);
315
+ }
316
+
317
+ // Get formatted limits for UI display
318
+ const formatted = await sdk.getFormattedSpendingLimits();
319
+ console.log(`${formatted.dailyUsedPercentage}% of daily limit used`);
320
+ console.log(`Resets in: ${formatted.timeUntilReset}`);
321
+
322
+ // Update daily limit (requires passkey signature)
323
+ const prepared = await sdk.prepareSetDailyLimit(ethers.parseEther('5.0'));
324
+ await sdk.executeTransfer(prepared, signer);
325
+ ```
140
326
 
141
- ### Chain Clients
327
+ ### Error Handling
328
+
329
+ All SDK methods throw `VeridexError` with typed error codes, so you can handle errors programmatically:
142
330
 
143
331
  ```typescript
144
- import { EVMClient } from '@veridex/sdk/chains/evm';
145
- import { SolanaClient } from '@veridex/sdk/chains/solana';
146
- import { AptosClient } from '@veridex/sdk/chains/aptos';
147
- import { SuiClient } from '@veridex/sdk/chains/sui';
148
- import { StarknetClient } from '@veridex/sdk/chains/starknet';
332
+ import { VeridexError, VeridexErrorCode, normalizeError } from '@veridex/sdk';
333
+
334
+ try {
335
+ await sdk.executeTransfer(prepared, signer);
336
+ } catch (err) {
337
+ if (err instanceof VeridexError) {
338
+ switch (err.code) {
339
+ case VeridexErrorCode.NO_CREDENTIAL:
340
+ console.log('Register a passkey first');
341
+ break;
342
+ case VeridexErrorCode.INSUFFICIENT_BALANCE:
343
+ console.log('Not enough funds');
344
+ break;
345
+ case VeridexErrorCode.RPC_ERROR:
346
+ console.log('Network issue — retry');
347
+ break;
348
+ default:
349
+ console.log(`SDK error [${err.code}]: ${err.message}`);
350
+ }
351
+ }
352
+ }
149
353
  ```
150
354
 
151
- ### Utilities
355
+ `normalizeError()` converts chain-specific errors (Solana program errors, EVM reverts, Starknet failures) into consistent `VeridexError` instances:
152
356
 
153
357
  ```typescript
154
- import {
155
- encodeTransferAction,
156
- encodeBridgeAction,
157
- parseVAA,
158
- fetchVAA,
159
- } from '@veridex/sdk';
358
+ try {
359
+ await solanaClient.dispatch(payload);
360
+ } catch (err) {
361
+ const normalized = normalizeError(err);
362
+ // normalized is always a VeridexError, even if the original was a raw RPC error
363
+ console.log(normalized.code, normalized.message);
364
+ }
160
365
  ```
161
366
 
162
- ### Constants
367
+ Available error codes: `NO_CREDENTIAL`, `VAULT_NOT_FOUND`, `INSUFFICIENT_BALANCE`, `BRIDGE_FAILED`, `RELAYER_ERROR`, `RPC_ERROR`, `TRANSACTION_FAILED`, `INVALID_ACTION`, `INVALID_PARAMS`, `UNAUTHORIZED`, `UNSUPPORTED_CHAIN`, `UNSUPPORTED_FEATURE`, `TIMEOUT`, `UNKNOWN`.
368
+
369
+ ### Feature Discovery
370
+
371
+ Not all chains support the same features. Use `supportsFeature()` and `getCapabilityMatrix()` to check before calling:
163
372
 
164
373
  ```typescript
165
- import {
166
- WORMHOLE_CHAIN_IDS,
167
- TESTNET_CHAINS,
168
- MAINNET_CHAINS,
169
- } from '@veridex/sdk';
374
+ // Check a single feature
375
+ if (sdk.supportsFeature('sessions')) {
376
+ const session = await sessionManager.createSession({ duration: 3600 });
377
+ }
378
+
379
+ // Full capability matrix for UI toggling
380
+ const caps = sdk.getCapabilityMatrix();
381
+ console.log(caps);
382
+ // {
383
+ // sessions: true,
384
+ // bridging: true,
385
+ // gaslessTransfers: true,
386
+ // spendingLimits: true,
387
+ // multisig: true,
388
+ // batchOperations: true,
389
+ // ...
390
+ // }
170
391
  ```
171
392
 
172
- ## Security
393
+ ### Balance Watching
173
394
 
174
- - **Passkeys Only** - No EOA or seed phrase assumptions
175
- - **RIP-7212 Support** - Native P-256 verification (~3,450 gas)
176
- - **FCL Fallback** - Software verification when precompile unavailable
177
- - **Wormhole VAA** - 13/19 guardian quorum for cross-chain messages
178
- - **Replay Protection** - Nonce-based action deduplication
395
+ Subscribe to real-time balance changes with polling-based watchers:
179
396
 
180
- ## Browser Support
397
+ ```typescript
398
+ import { BalanceWatcher } from '@veridex/sdk';
181
399
 
182
- WebAuthn requires a secure context (HTTPS) and a compatible browser:
400
+ const watcher = new BalanceWatcher(sdk, {
401
+ pollIntervalMs: 5000, // Poll every 5s (default: 10s)
402
+ cacheTtlMs: 3000, // Cache results for 3s (default: 5s)
403
+ });
183
404
 
184
- | Browser | Minimum Version |
185
- |---------|-----------------|
186
- | Chrome | 67+ |
187
- | Firefox | 60+ |
188
- | Safari | 14+ |
189
- | Edge | 18+ |
405
+ // Subscribe to balance updates
406
+ const unsubscribe = watcher.subscribe((balances) => {
407
+ for (const b of balances.tokens) {
408
+ console.log(`${b.token.symbol}: ${b.formatted}`);
409
+ }
410
+ });
411
+
412
+ // Start watching
413
+ watcher.start();
414
+
415
+ // Later, stop and clean up
416
+ watcher.stop();
417
+ unsubscribe();
418
+ ```
419
+
420
+ ### Multi-Chain Portfolio
421
+
422
+ Get a combined view of vault addresses and balances across all supported chains:
423
+
424
+ ```typescript
425
+ // All vault addresses in one call
426
+ const addresses = sdk.getMultiChainAddresses();
427
+ // { 30: '0xabc...', 24: '0xdef...', 1: 'So1ana...' }
428
+
429
+ // Full portfolio across chains
430
+ const portfolio = await sdk.getMultiChainPortfolio();
431
+ for (const entry of portfolio) {
432
+ console.log(`${entry.chainName}: $${entry.totalUsdValue}`);
433
+ for (const token of entry.tokens) {
434
+ console.log(` ${token.token.symbol}: ${token.formatted}`);
435
+ }
436
+ }
437
+
438
+ // Or query specific chains only
439
+ const evmPortfolio = await sdk.getMultiChainPortfolio([30, 24, 23]);
440
+ ```
441
+
442
+ ### Enterprise Manager
443
+
444
+ Batch operations with concurrency control and lifecycle callbacks for production workloads:
445
+
446
+ ```typescript
447
+ import { EnterpriseManager } from '@veridex/sdk';
448
+
449
+ const enterprise = new EnterpriseManager({
450
+ sdk,
451
+ signer,
452
+ maxConcurrency: 5, // Run up to 5 ops in parallel (default: 3)
453
+ });
454
+
455
+ // Batch vault creation
456
+ const vaults = await enterprise.batchCreateVaults(
457
+ { keyHashes: ['0xabc...', '0xdef...', '0x123...'] },
458
+ (event) => {
459
+ // Lifecycle callback — track progress in UI
460
+ console.log(`[${event.status}] Item ${event.index}: ${event.message}`);
461
+ },
462
+ );
463
+
464
+ // Batch transfers
465
+ const transfers = await enterprise.batchTransfer(
466
+ {
467
+ transfers: [
468
+ { targetChain: 10004, token: '0x...', recipient: '0x...', amount: 1000000n },
469
+ { targetChain: 10005, token: '0x...', recipient: '0x...', amount: 2000000n },
470
+ ],
471
+ },
472
+ (event) => console.log(`Transfer ${event.index}: ${event.status}`),
473
+ );
474
+ console.log(`${transfers.successful}/${transfers.total} succeeded`);
475
+
476
+ // Batch spending limits
477
+ const limits = await enterprise.batchSetSpendingLimits({
478
+ limits: [
479
+ { vaultAddress: '0x...', dailyLimit: 5000000000000000000n },
480
+ { vaultAddress: '0x...', dailyLimit: 10000000000000000000n },
481
+ ],
482
+ });
483
+ ```
484
+
485
+ ## Chain Clients
486
+
487
+ Each chain has a dedicated client implementing the `ChainClient` interface:
488
+
489
+ ```typescript
490
+ import { EVMClient } from '@veridex/sdk';
491
+ import { SolanaClient } from '@veridex/sdk';
492
+ import { AptosClient } from '@veridex/sdk';
493
+ import { SuiClient } from '@veridex/sdk';
494
+ import { StarknetClient } from '@veridex/sdk';
495
+ import { StacksClient } from '@veridex/sdk';
496
+
497
+ // Or use subpath imports
498
+ import { EVMClient } from '@veridex/sdk/chains/evm';
499
+ import { StacksClient } from '@veridex/sdk/chains/stacks';
500
+ ```
501
+
502
+ All clients support:
503
+ - `buildTransferPayload()` — Build token transfer payloads
504
+ - `buildExecutePayload()` — Build arbitrary execution payloads
505
+ - `buildBridgePayload()` — Build cross-chain bridge payloads
506
+ - `dispatch()` — Submit signed actions with a signer
507
+ - `computeVaultAddress()` — Derive deterministic vault address
508
+ - `vaultExists()` — Check if vault is deployed
509
+ - `createVault()` — Deploy a vault
510
+ - `getNonce()` — Get replay-protection nonce
511
+ - `getMessageFee()` — Get Wormhole message fee
512
+
513
+ ### Stacks-Specific
514
+
515
+ Stacks has unique capabilities leveraged by the SDK:
516
+
517
+ ```typescript
518
+ import {
519
+ StacksClient,
520
+ stacksCompressPublicKey,
521
+ stacksRsToCompactSignature,
522
+ stacksDerToCompactSignature,
523
+ stacksComputeKeyHash,
524
+ buildStxWithdrawalPostConditions,
525
+ isValidStacksPrincipal,
526
+ getStacksExplorerTxUrl,
527
+ } from '@veridex/sdk';
528
+
529
+ // Native secp256r1 verification (no ZK proofs needed)
530
+ // Native sponsored transactions (gasless built-in)
531
+ // Post-conditions for protocol-level spending safety
532
+ ```
533
+
534
+ ## Factory Functions
535
+
536
+ ```typescript
537
+ import {
538
+ createSDK, // Main factory — createSDK('base', { network: 'testnet' })
539
+ createHubSDK, // Shortcut for Base hub — createHubSDK()
540
+ createTestnetSDK, // Force testnet — createTestnetSDK('optimism')
541
+ createMainnetSDK, // Force mainnet — createMainnetSDK('base')
542
+ createSessionSDK, // Session-enabled — createSessionSDK('base')
543
+ } from '@veridex/sdk';
544
+
545
+ // Check supported chains
546
+ import { getSupportedChains, getChainConfig, isChainSupported } from '@veridex/sdk';
190
547
 
191
- ## TypeScript
548
+ const chains = getSupportedChains('testnet');
549
+ console.log('Supported:', chains); // ['base', 'ethereum', 'optimism', ...]
192
550
 
193
- Full TypeScript support with comprehensive type definitions:
551
+ const config = getChainConfig('base', 'testnet');
552
+ console.log('RPC:', config.rpcUrl);
553
+ console.log('Chain ID:', config.chainId);
554
+ ```
555
+
556
+ ## Types
194
557
 
195
558
  ```typescript
196
559
  import type {
197
560
  ChainName,
561
+ ChainClient,
562
+ ChainConfig,
198
563
  NetworkType,
199
564
  SimpleSDKConfig,
200
565
  TransferParams,
566
+ ExecuteParams,
201
567
  BridgeParams,
202
568
  SessionKey,
569
+ SessionConfig,
570
+ WebAuthnSignature,
571
+ PasskeyCredential,
572
+ DispatchResult,
573
+ VaultCreationResult,
574
+ PreparedTransfer,
575
+ TransferResult,
576
+ PreparedBridge,
577
+ BridgeResult,
578
+ PortfolioBalance,
579
+ TokenBalance,
580
+ SpendingLimits,
581
+ LimitCheckResult,
582
+ IdentityState,
583
+ UnifiedIdentity,
203
584
  } from '@veridex/sdk';
204
585
  ```
205
586
 
587
+ ## Security
588
+
589
+ - **Passkeys only** — No EOA, no seed phrases, no browser extensions
590
+ - **RIP-7212** — Native P-256 verification (~3,450 gas on EVM)
591
+ - **FCL fallback** — Software verification when precompile unavailable
592
+ - **Wormhole VAA** — 13/19 guardian quorum for cross-chain messages
593
+ - **Custom bridge** — Multi-relayer threshold attestations for Starknet
594
+ - **Replay protection** — Nonce-based action deduplication on all chains
595
+ - **Post-conditions** — Protocol-level spending caps on Stacks
596
+
597
+ ## Frontend Requirement
598
+
599
+ > **Important:** This SDK requires a **browser frontend** for passkey operations. WebAuthn (passkeys) can only be created and used in a secure browser context — `sdk.passkey.register()` and `sdk.passkey.authenticate()` trigger native OS biometric prompts (FaceID, TouchID, Windows Hello) that cannot run in Node.js or server-side environments.
600
+
601
+ **You need a frontend to:**
602
+ - **Register passkeys** — `sdk.passkey.register()` must be called from a user-initiated browser event (e.g., button click)
603
+ - **Authenticate** — `sdk.passkey.authenticate()` shows the platform passkey picker in the browser
604
+ - **Store credentials** — Passkey credentials are stored in the browser's platform authenticator (iCloud Keychain, Google Password Manager, etc.)
605
+
606
+ **What can run server-side:**
607
+ - Verifying transactions on-chain
608
+ - Querying balances (`sdk.getVaultBalances()`)
609
+ - Relayer API calls
610
+ - Session key operations (after initial passkey-based creation on the frontend)
611
+
612
+ **Minimal frontend example (React):**
613
+
614
+ ```tsx
615
+ 'use client';
616
+ import { createSDK } from '@veridex/sdk';
617
+
618
+ const sdk = createSDK('base', { network: 'testnet' });
619
+
620
+ export function PasskeyWallet() {
621
+ const handleCreate = async () => {
622
+ // Must be triggered by user interaction (button click)
623
+ const credential = await sdk.passkey.register('user@example.com', 'My Wallet');
624
+ console.log('Vault:', sdk.getVaultAddress());
625
+ };
626
+
627
+ const handleLogin = async () => {
628
+ const { credential } = await sdk.passkey.authenticate();
629
+ console.log('Authenticated:', credential.keyHash);
630
+ };
631
+
632
+ return (
633
+ <div>
634
+ <button onClick={handleCreate}>Create Wallet</button>
635
+ <button onClick={handleLogin}>Login</button>
636
+ </div>
637
+ );
638
+ }
639
+ ```
640
+
641
+ For a complete frontend example, see the [test-app](https://github.com/Veridex-Protocol/demo/tree/main/test-app) or the [React integration guide](https://docs.veridex.network/integrations/react).
642
+
643
+ ## Browser Support
644
+
645
+ WebAuthn requires HTTPS and a compatible browser:
646
+
647
+ | Browser | Minimum Version |
648
+ |---------|-----------------|
649
+ | Chrome | 67+ |
650
+ | Firefox | 60+ |
651
+ | Safari | 14+ |
652
+ | Edge | 79+ |
653
+
654
+ ## Related Packages
655
+
656
+ | Package | Description |
657
+ |---------|-------------|
658
+ | [`@veridex/agentic-payments`](https://www.npmjs.com/package/@veridex/agentic-payments) | Agent payment SDK — x402, UCP, ACP, AP2, ERC-8004 identity |
659
+ | `@veridex/relayer` | Transaction relayer for gasless execution |
660
+ | `@veridex/contracts` | Smart contracts (EVM, Solana, Aptos, Sui, Starknet, Stacks) |
661
+
206
662
  ## License
207
663
 
208
664
  MIT
209
665
 
210
666
  ## Links
211
667
 
212
- - [Documentation](https://docs.veridex.io)
668
+ - [Documentation](https://docs.veridex.network)
213
669
  - [GitHub](https://github.com/Veridex-Protocol/sdk)
670
+ - [npm](https://www.npmjs.com/package/@veridex/sdk)
214
671
  - [Discord](https://discord.gg/veridex)
215
672
  - [Twitter](https://twitter.com/VeridexProtocol)