@fenelabs/fene-sdk 0.3.2 → 0.3.3
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.
- package/README.md +151 -398
- package/dist/index.d.mts +260 -1197
- package/dist/index.d.ts +260 -1197
- package/dist/index.js +343 -1042
- package/dist/index.mjs +333 -1018
- package/package.json +27 -44
- package/CHANGELOG.md +0 -176
package/README.md
CHANGED
|
@@ -1,485 +1,238 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @resonance/sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
TypeScript SDK for the Resonance API.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
9
|
-
# or
|
|
10
|
-
yarn add @fenelabs/fene-sdk
|
|
11
|
-
# or
|
|
12
|
-
pnpm add @fenelabs/fene-sdk
|
|
8
|
+
pnpm add @resonance/sdk
|
|
13
9
|
```
|
|
14
10
|
|
|
15
11
|
## Quick Start
|
|
16
12
|
|
|
17
13
|
```typescript
|
|
18
|
-
import {
|
|
14
|
+
import { createResonanceClient } from "@resonance/sdk";
|
|
19
15
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
apiUrl: 'https://api.fene.network',
|
|
23
|
-
timeout: 30000, // Optional, default 30s
|
|
16
|
+
const client = createResonanceClient({
|
|
17
|
+
baseUrl: "https://api.fene.network",
|
|
24
18
|
});
|
|
25
19
|
|
|
26
|
-
// Get
|
|
27
|
-
const stats = await
|
|
28
|
-
console.log(
|
|
20
|
+
// Get network stats
|
|
21
|
+
const stats = await client.getNetworkStats();
|
|
22
|
+
console.log(`Total validators: ${stats.total_validators}`);
|
|
29
23
|
|
|
30
|
-
// Get
|
|
31
|
-
const
|
|
32
|
-
console.log(
|
|
24
|
+
// Get APR
|
|
25
|
+
const apr = await client.getNetworkAPR();
|
|
26
|
+
console.log(`Network APR: ${apr.network_apr}%`);
|
|
33
27
|
```
|
|
34
28
|
|
|
35
29
|
## Authentication
|
|
36
30
|
|
|
37
|
-
The SDK supports wallet-based authentication using Web3 providers:
|
|
38
|
-
|
|
39
31
|
```typescript
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
32
|
+
import { createResonanceClient } from "@resonance/sdk";
|
|
33
|
+
import { signMessage } from "viem/wallet";
|
|
42
34
|
|
|
43
|
-
const
|
|
44
|
-
|
|
35
|
+
const client = createResonanceClient({
|
|
36
|
+
baseUrl: "https://api.fene.network",
|
|
37
|
+
onTokenExpired: () => {
|
|
38
|
+
console.log("Token expired, please re-authenticate");
|
|
39
|
+
},
|
|
45
40
|
});
|
|
46
41
|
|
|
47
|
-
//
|
|
48
|
-
const
|
|
49
|
-
const authResponse = await sdk.auth.connectWallet(provider, 'delegator');
|
|
42
|
+
// 1. Get nonce
|
|
43
|
+
const { message } = await client.getNonce("0x...");
|
|
50
44
|
|
|
51
|
-
//
|
|
52
|
-
|
|
45
|
+
// 2. Sign message (using viem or wagmi)
|
|
46
|
+
const signature = await signMessage({ message });
|
|
53
47
|
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
48
|
+
// 3. Verify and get JWT
|
|
49
|
+
const auth = await client.verify("0x...", signature);
|
|
50
|
+
console.log(`Logged in as: ${auth.role}`);
|
|
58
51
|
|
|
59
|
-
//
|
|
60
|
-
|
|
52
|
+
// Now authenticated requests work
|
|
53
|
+
await client.updateGeoLocation({ latitude: 0, longitude: 0, node_type: "rpc" });
|
|
61
54
|
```
|
|
62
55
|
|
|
63
|
-
##
|
|
56
|
+
## Error Handling
|
|
64
57
|
|
|
65
|
-
|
|
58
|
+
The SDK provides structured error handling matching the API's error system:
|
|
66
59
|
|
|
67
60
|
```typescript
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const breakdown = await sdk.global.getNetworkAPRBreakdown();
|
|
76
|
-
|
|
77
|
-
// Get delegator leaderboard
|
|
78
|
-
const delegatorLeaderboard = await sdk.global.getLeaderboardDelegators(10, 0);
|
|
79
|
-
|
|
80
|
-
// Get validator leaderboard
|
|
81
|
-
const validatorLeaderboard = await sdk.global.getLeaderboardValidators(10, 0);
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### Validators
|
|
85
|
-
|
|
86
|
-
```typescript
|
|
87
|
-
// Get all validators
|
|
88
|
-
const allValidators = await sdk.validators.getAll();
|
|
89
|
-
|
|
90
|
-
// Get specific validator details
|
|
91
|
-
const validator = await sdk.validators.get('0x1234...');
|
|
92
|
-
|
|
93
|
-
// Get validator delegators
|
|
94
|
-
const delegators = await sdk.validators.getDelegators('0x1234...');
|
|
95
|
-
|
|
96
|
-
// Get validator stake breakdown
|
|
97
|
-
const stakeBreakdown = await sdk.validators.getStakeBreakdown('0x1234...');
|
|
98
|
-
|
|
99
|
-
// Get validator epoch details
|
|
100
|
-
const epochData = await sdk.validators.getEpoch('0x1234...', 100);
|
|
101
|
-
|
|
102
|
-
// Get validator history
|
|
103
|
-
const history = await sdk.validators.getHistory('0x1234...', 1, 100);
|
|
104
|
-
|
|
105
|
-
// Get validator withdrawals
|
|
106
|
-
const withdrawals = await sdk.validators.getWithdrawals('0x1234...', 50, 0);
|
|
107
|
-
|
|
108
|
-
// Get validator metrics
|
|
109
|
-
const metrics = await sdk.validators.getMetrics('0x1234...');
|
|
110
|
-
|
|
111
|
-
// Get validator slashing events
|
|
112
|
-
const slashing = await sdk.validators.getSlashing('0x1234...');
|
|
113
|
-
|
|
114
|
-
// Get validator APR
|
|
115
|
-
const validatorAPR = await sdk.validators.getAPR('0x1234...');
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
### Delegators
|
|
119
|
-
|
|
120
|
-
```typescript
|
|
121
|
-
// Get all delegators
|
|
122
|
-
const allDelegators = await sdk.delegators.getAll();
|
|
123
|
-
|
|
124
|
-
// Get specific delegator details
|
|
125
|
-
const delegator = await sdk.delegators.get('0xabcd...');
|
|
126
|
-
|
|
127
|
-
// Get delegator stakes breakdown
|
|
128
|
-
const stakes = await sdk.delegators.getStakes('0xabcd...');
|
|
129
|
-
|
|
130
|
-
// Get delegator rewards history
|
|
131
|
-
const rewards = await sdk.delegators.getRewards('0xabcd...', 50, 0);
|
|
61
|
+
import {
|
|
62
|
+
createResonanceClient,
|
|
63
|
+
ResonanceError,
|
|
64
|
+
ErrorCode,
|
|
65
|
+
isAuthError,
|
|
66
|
+
isNotFoundError,
|
|
67
|
+
} from "@resonance/sdk";
|
|
132
68
|
|
|
133
|
-
|
|
134
|
-
const withdrawals = await sdk.delegators.getWithdrawals('0xabcd...', 50, 0);
|
|
69
|
+
const client = createResonanceClient({ baseUrl: "https://api.fene.network" });
|
|
135
70
|
|
|
136
|
-
|
|
137
|
-
const
|
|
71
|
+
try {
|
|
72
|
+
const validator = await client.getValidator("0xinvalid");
|
|
73
|
+
} catch (error) {
|
|
74
|
+
if (error instanceof ResonanceError) {
|
|
75
|
+
console.log(`Error code: ${error.code}`);
|
|
76
|
+
console.log(`Message: ${error.message}`);
|
|
77
|
+
console.log(`Status: ${error.statusCode}`);
|
|
78
|
+
|
|
79
|
+
// Check specific error types
|
|
80
|
+
if (error.is(ErrorCode.VALIDATOR_NOT_FOUND)) {
|
|
81
|
+
// Handle validator not found
|
|
82
|
+
}
|
|
138
83
|
|
|
139
|
-
//
|
|
140
|
-
|
|
84
|
+
// Or use helper functions
|
|
85
|
+
if (isAuthError(error)) {
|
|
86
|
+
// Re-authenticate
|
|
87
|
+
} else if (isNotFoundError(error)) {
|
|
88
|
+
// Handle not found
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
141
92
|
```
|
|
142
93
|
|
|
143
|
-
###
|
|
144
|
-
|
|
145
|
-
```typescript
|
|
146
|
-
// Validate a referral code
|
|
147
|
-
const validation = await sdk.referrals.validate('REF123');
|
|
148
|
-
|
|
149
|
-
// Create a new referral code (requires authentication)
|
|
150
|
-
const referralCode = await sdk.referrals.create({
|
|
151
|
-
validator_address: '0x1234...',
|
|
152
|
-
max_quota: 100,
|
|
153
|
-
expires_in_days: 30,
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
// Apply a referral code
|
|
157
|
-
await sdk.referrals.apply({
|
|
158
|
-
referral_code: 'REF123',
|
|
159
|
-
delegator_address: '0xabcd...',
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
// Delete a referral code (requires authentication)
|
|
163
|
-
await sdk.referrals.delete('REF123');
|
|
94
|
+
### Error Codes
|
|
164
95
|
|
|
165
|
-
|
|
166
|
-
await sdk.referrals.unlink('0xabcd...');
|
|
96
|
+
The SDK recognizes these error codes from the API:
|
|
167
97
|
|
|
168
|
-
|
|
169
|
-
|
|
98
|
+
- **Validator**: `VALIDATOR_NOT_FOUND`, `VALIDATOR_INACTIVE`
|
|
99
|
+
- **Delegator**: `DELEGATOR_NOT_FOUND`, `NOT_WHITELISTED`
|
|
100
|
+
- **Referral**: `REFERRAL_KEY_INVALID`, `REFERRAL_KEY_EXPIRED`, `REFERRAL_KEY_USED`
|
|
101
|
+
- **Auth**: `INVALID_SIGNATURE`, `NONCE_EXPIRED`, `UNAUTHORIZED`
|
|
102
|
+
- **Service**: `RPC_UNAVAILABLE`, `CACHE_UNAVAILABLE`, `DATABASE_UNAVAILABLE`
|
|
103
|
+
- **General**: `BAD_REQUEST`, `INTERNAL_ERROR`, `RATE_LIMITED`
|
|
170
104
|
|
|
171
|
-
|
|
172
|
-
const validatorRef = await sdk.referrals.getValidatorReferral('0x1234...');
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
### Slashing
|
|
105
|
+
## Architecture
|
|
176
106
|
|
|
177
|
-
|
|
178
|
-
// Get all slashing events
|
|
179
|
-
const allEvents = await sdk.slashing.getEvents();
|
|
107
|
+
### Caching
|
|
180
108
|
|
|
181
|
-
|
|
182
|
-
const validatorEvents = await sdk.slashing.getEvents('0x1234...', 50, 0);
|
|
183
|
-
```
|
|
109
|
+
The Resonance API implements **server-side Redis caching** with graceful degradation. The SDK does not implement client-side caching as all caching is handled by the API layer. This ensures:
|
|
184
110
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
```typescript
|
|
190
|
-
// Get protocol-level statistics
|
|
191
|
-
const protocolStats = await sdk.analytics.getProtocolStats();
|
|
192
|
-
console.log('Total Staking:', protocolStats.TotalStaking);
|
|
193
|
-
console.log('Active Validators:', protocolStats.ActiveValidators);
|
|
194
|
-
|
|
195
|
-
// Check sync status of analytics workers
|
|
196
|
-
const syncStatus = await sdk.analytics.getSyncStatus();
|
|
197
|
-
console.log('Protocol Sync Status:', syncStatus.protocol_sync.status);
|
|
198
|
-
console.log('Last Synced Block:', syncStatus.protocol_sync.last_block);
|
|
199
|
-
|
|
200
|
-
// Get all validators with analytics data (paginated)
|
|
201
|
-
const validators = await sdk.analytics.getAllValidators({
|
|
202
|
-
limit: 20,
|
|
203
|
-
offset: 0,
|
|
204
|
-
status: 'active',
|
|
205
|
-
});
|
|
111
|
+
- Consistent data across all API consumers
|
|
112
|
+
- Reduced load on blockchain RPC nodes
|
|
113
|
+
- Automatic cache invalidation on chain state changes
|
|
114
|
+
- Cache TTLs optimized per endpoint (10s to 5min)
|
|
206
115
|
|
|
207
|
-
|
|
208
|
-
const topValidators = await sdk.analytics.getTopValidators(10);
|
|
209
|
-
topValidators.data.forEach((v, i) => {
|
|
210
|
-
console.log(`#${i + 1}: ${v.moniker} - ${v.uptime}% uptime`);
|
|
211
|
-
});
|
|
116
|
+
### Authentication
|
|
212
117
|
|
|
213
|
-
|
|
214
|
-
const validatorAnalytics = await sdk.analytics.getValidatorAnalytics('0x1234...');
|
|
215
|
-
console.log('Uptime:', validatorAnalytics.uptime);
|
|
216
|
-
console.log('Signed Blocks:', validatorAnalytics.signed_blocks);
|
|
217
|
-
console.log('Total Stakers:', validatorAnalytics.total_stakers);
|
|
118
|
+
The SDK uses a standard Web3 authentication flow:
|
|
218
119
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
});
|
|
120
|
+
1. Request a nonce from the API (`getNonce`)
|
|
121
|
+
2. Sign the message with your wallet (using viem, wagmi, etc.)
|
|
122
|
+
3. Submit signature for verification (`verify`)
|
|
123
|
+
4. Receive JWT token for authenticated requests
|
|
224
124
|
|
|
225
|
-
|
|
226
|
-
console.log('Total Stakers:', rewardsPage1.summary.total_stakers);
|
|
227
|
-
console.log('Has More Data:', rewardsPage1.metadata.has_more);
|
|
125
|
+
The token is automatically included in all subsequent requests and managed by the client.
|
|
228
126
|
|
|
229
|
-
|
|
230
|
-
if (rewardsPage1.metadata.has_more) {
|
|
231
|
-
const rewardsPage2 = await sdk.analytics.getValidatorRewards('0x1234...', {
|
|
232
|
-
limit: 50,
|
|
233
|
-
offset: 50,
|
|
234
|
-
});
|
|
235
|
-
}
|
|
127
|
+
## API Reference
|
|
236
128
|
|
|
237
|
-
|
|
238
|
-
const allRewards = await sdk.analytics.getAllValidatorRewards('0x1234...', {
|
|
239
|
-
batchSize: 50,
|
|
240
|
-
maxPages: 10, // Safety limit
|
|
241
|
-
});
|
|
129
|
+
### Auth
|
|
242
130
|
|
|
243
|
-
|
|
244
|
-
|
|
131
|
+
- `getNonce(address)` - Get authentication nonce
|
|
132
|
+
- `verify(address, signature)` - Verify signature and get JWT
|
|
245
133
|
|
|
246
|
-
|
|
247
|
-
- Analytics data is sourced from subgraph indexing and may lag behind real-time blockchain state
|
|
248
|
-
- Always check `metadata.cached` and `metadata.stale` flags in responses
|
|
249
|
-
- The rewards endpoint is heavy and **requires pagination** - never fetch without limit/offset
|
|
250
|
-
- Use `getSyncStatus()` to verify data freshness before making critical decisions
|
|
134
|
+
### Validators
|
|
251
135
|
|
|
252
|
-
|
|
136
|
+
- `getValidators()` - Get all validators
|
|
137
|
+
- `getActiveValidators()` - Get active validators
|
|
138
|
+
- `getCandidates()` - Get validator candidates
|
|
139
|
+
- `getValidator(address)` - Get validator details
|
|
140
|
+
- `getValidatorDelegators(address)` - Get validator's delegators
|
|
253
141
|
|
|
254
|
-
|
|
142
|
+
### Delegators
|
|
255
143
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
isStaleData,
|
|
260
|
-
isCachedData,
|
|
261
|
-
isSyncHealthy,
|
|
262
|
-
getSyncLag,
|
|
263
|
-
getDataFreshness,
|
|
264
|
-
formatNumber,
|
|
265
|
-
weiToEther,
|
|
266
|
-
withRetry,
|
|
267
|
-
} from '@avenbreaks/resonance-sdk';
|
|
268
|
-
|
|
269
|
-
// Error handling
|
|
270
|
-
try {
|
|
271
|
-
const validator = await sdk.analytics.getValidatorAnalytics(address);
|
|
272
|
-
} catch (error) {
|
|
273
|
-
if (isValidatorNotFound(error)) {
|
|
274
|
-
console.log('Validator does not exist');
|
|
275
|
-
}
|
|
276
|
-
}
|
|
144
|
+
- `getDelegator(address)` - Get delegator info
|
|
145
|
+
- `getDelegatorStakes(address)` - Get delegator stakes
|
|
146
|
+
- `getDelegatorRewards(address)` - Get delegator rewards
|
|
277
147
|
|
|
278
|
-
|
|
279
|
-
const rewards = await sdk.analytics.getValidatorRewards(address, { limit: 50 });
|
|
280
|
-
if (isStaleData(rewards)) {
|
|
281
|
-
console.warn('Data may be outdated');
|
|
282
|
-
}
|
|
148
|
+
### Referral
|
|
283
149
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
if (
|
|
287
|
-
console.log('Sync is healthy');
|
|
288
|
-
}
|
|
150
|
+
- `getReferralKey(key)` - Get referral key info
|
|
151
|
+
- `getValidatorKeys(address)` - Get validator's referral keys
|
|
152
|
+
- `checkWhitelist(data)` - Check if whitelisted (requires auth)
|
|
289
153
|
|
|
290
|
-
|
|
291
|
-
const rewardsWithRetry = await withRetry(
|
|
292
|
-
() => sdk.analytics.getValidatorRewards(address, { limit: 100 }),
|
|
293
|
-
{
|
|
294
|
-
maxRetries: 3,
|
|
295
|
-
initialDelay: 1000,
|
|
296
|
-
onRetry: (error, attempt, delay) => {
|
|
297
|
-
console.log(`Retry ${attempt} after ${delay}ms`);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
);
|
|
154
|
+
### Geo
|
|
301
155
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
```
|
|
156
|
+
- `getGeoNodes()` - Get all geo nodes
|
|
157
|
+
- `getGeoValidators()` - Get validator locations
|
|
158
|
+
- `getGeoStats()` - Get geo statistics
|
|
159
|
+
- `updateGeoLocation(data)` - Update geo location (requires auth)
|
|
307
160
|
|
|
308
|
-
|
|
161
|
+
### Stats
|
|
309
162
|
|
|
310
|
-
|
|
163
|
+
- `getNetworkStats()` - Get network statistics
|
|
164
|
+
- `getCurrentEpoch()` - Get current epoch info
|
|
311
165
|
|
|
312
|
-
|
|
313
|
-
const sdk = new ResonanceSDK({
|
|
314
|
-
apiUrl: 'https://api.fene.network',
|
|
315
|
-
headers: {
|
|
316
|
-
'X-Custom-Header': 'value',
|
|
317
|
-
},
|
|
318
|
-
});
|
|
166
|
+
### APR
|
|
319
167
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
```
|
|
168
|
+
- `getNetworkAPR()` - Get network-wide APR
|
|
169
|
+
- `getValidatorAPR(address)` - Get validator APR breakdown
|
|
323
170
|
|
|
324
|
-
###
|
|
171
|
+
### Storage
|
|
325
172
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
const validator = await sdk.validators.get('0x1234...');
|
|
329
|
-
} catch (error) {
|
|
330
|
-
if (error instanceof Error) {
|
|
331
|
-
console.error('API Error:', error.message);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
```
|
|
173
|
+
- `uploadAvatar(file)` - Upload avatar (requires auth)
|
|
174
|
+
- `getAvatar(address)` - Get avatar URL
|
|
335
175
|
|
|
336
|
-
###
|
|
176
|
+
### Analytics
|
|
337
177
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
apiUrl: 'https://api.fene.network',
|
|
341
|
-
timeout: 60000, // 60 seconds
|
|
342
|
-
});
|
|
343
|
-
```
|
|
178
|
+
- `getDailyBlockStats(days?)` - Get daily block stats
|
|
179
|
+
- `getValidatorRewardHistory(address, limit?)` - Get reward history
|
|
344
180
|
|
|
345
|
-
##
|
|
181
|
+
## Types
|
|
346
182
|
|
|
347
|
-
|
|
183
|
+
All types are exported for TypeScript users:
|
|
348
184
|
|
|
349
185
|
```typescript
|
|
350
186
|
import type {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
function ValidatorList() {
|
|
373
|
-
const [validators, setValidators] = useState([]);
|
|
374
|
-
const [loading, setLoading] = useState(true);
|
|
375
|
-
|
|
376
|
-
useEffect(() => {
|
|
377
|
-
const fetchValidators = async () => {
|
|
378
|
-
try {
|
|
379
|
-
const data = await sdk.validators.getAll();
|
|
380
|
-
setValidators(data);
|
|
381
|
-
} catch (error) {
|
|
382
|
-
console.error('Failed to fetch validators:', error);
|
|
383
|
-
} finally {
|
|
384
|
-
setLoading(false);
|
|
385
|
-
}
|
|
386
|
-
};
|
|
387
|
-
|
|
388
|
-
fetchValidators();
|
|
389
|
-
}, []);
|
|
390
|
-
|
|
391
|
-
if (loading) return <div>Loading...</div>;
|
|
392
|
-
|
|
393
|
-
return (
|
|
394
|
-
<div>
|
|
395
|
-
{validators.map((validator) => (
|
|
396
|
-
<div key={validator.address}>{validator.address}</div>
|
|
397
|
-
))}
|
|
398
|
-
</div>
|
|
399
|
-
);
|
|
400
|
-
}
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
## Next.js Example
|
|
404
|
-
|
|
405
|
-
```typescript
|
|
406
|
-
// app/page.tsx
|
|
407
|
-
import { ResonanceSDK } from '@fenelabs/fene-sdk';
|
|
408
|
-
|
|
409
|
-
const sdk = new ResonanceSDK({
|
|
410
|
-
apiUrl: process.env.NEXT_PUBLIC_API_URL || 'https://api.fene.network',
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
export default async function HomePage() {
|
|
414
|
-
const stats = await sdk.global.getStats();
|
|
415
|
-
|
|
416
|
-
return (
|
|
417
|
-
<div>
|
|
418
|
-
<h1>Network Stats</h1>
|
|
419
|
-
<p>Total Validators: {stats.total_validators}</p>
|
|
420
|
-
<p>Total Delegators: {stats.total_delegators}</p>
|
|
421
|
-
<p>Total Stake: {stats.total_network_stake}</p>
|
|
422
|
-
</div>
|
|
423
|
-
);
|
|
424
|
-
}
|
|
187
|
+
Validator,
|
|
188
|
+
Delegator,
|
|
189
|
+
NetworkStats,
|
|
190
|
+
ValidatorAPR,
|
|
191
|
+
// Error types
|
|
192
|
+
ErrorCodeType,
|
|
193
|
+
APIErrorResponse,
|
|
194
|
+
} from "@resonance/sdk";
|
|
195
|
+
|
|
196
|
+
// Error handling utilities
|
|
197
|
+
import {
|
|
198
|
+
ResonanceError,
|
|
199
|
+
ErrorCode,
|
|
200
|
+
isResonanceError,
|
|
201
|
+
hasErrorCode,
|
|
202
|
+
isAuthError,
|
|
203
|
+
isNetworkError,
|
|
204
|
+
isNotFoundError,
|
|
205
|
+
} from "@resonance/sdk";
|
|
425
206
|
```
|
|
426
207
|
|
|
427
|
-
##
|
|
208
|
+
## Development
|
|
428
209
|
|
|
429
|
-
|
|
430
|
-
import { ResonanceSDK } from '@fenelabs/fene-sdk';
|
|
210
|
+
### Running Tests
|
|
431
211
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
async function main() {
|
|
437
|
-
// Get network statistics
|
|
438
|
-
const stats = await sdk.global.getStats();
|
|
439
|
-
console.log('Network Stats:', stats);
|
|
212
|
+
```bash
|
|
213
|
+
# Run all tests
|
|
214
|
+
pnpm test
|
|
440
215
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
console.log('Top 10 Validators:', leaderboard);
|
|
444
|
-
}
|
|
216
|
+
# Run tests in watch mode
|
|
217
|
+
pnpm test -- --watch
|
|
445
218
|
|
|
446
|
-
|
|
219
|
+
# Run tests with coverage
|
|
220
|
+
pnpm test -- --coverage
|
|
447
221
|
```
|
|
448
222
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
All API endpoints are available under the `/eth/v1` prefix. The SDK handles this automatically.
|
|
452
|
-
|
|
453
|
-
| Module | Endpoint Pattern | Description |
|
|
454
|
-
|--------|-----------------|-------------|
|
|
455
|
-
| Global | `/eth/v1/global` | Network statistics and leaderboards |
|
|
456
|
-
| Validators | `/eth/v1/validators/:address` | Validator information and history |
|
|
457
|
-
| Delegators | `/eth/v1/delegators/:address` | Delegator information and history |
|
|
458
|
-
| Referrals | `/eth/v1/referrals` | Referral code management |
|
|
459
|
-
| Slashing | `/eth/v1/slashing/events` | Slashing events |
|
|
460
|
-
|
|
461
|
-
## Development
|
|
223
|
+
### Building
|
|
462
224
|
|
|
463
225
|
```bash
|
|
464
|
-
# Install dependencies
|
|
465
|
-
pnpm install
|
|
466
|
-
|
|
467
226
|
# Build the SDK
|
|
468
|
-
pnpm build
|
|
227
|
+
pnpm run build
|
|
469
228
|
|
|
470
|
-
#
|
|
471
|
-
pnpm
|
|
229
|
+
# Watch mode for development
|
|
230
|
+
pnpm run dev
|
|
472
231
|
|
|
473
|
-
#
|
|
474
|
-
pnpm
|
|
232
|
+
# Type checking
|
|
233
|
+
pnpm run lint
|
|
475
234
|
```
|
|
476
235
|
|
|
477
236
|
## License
|
|
478
237
|
|
|
479
238
|
MIT
|
|
480
|
-
|
|
481
|
-
## Support
|
|
482
|
-
|
|
483
|
-
For issues and questions, please visit:
|
|
484
|
-
- GitHub Issues: https://github.com/fenelabs/fene-sdk/issues
|
|
485
|
-
- Documentation: https://docs.fene.network
|