ton-provider-system 0.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.
- package/README.md +421 -0
- package/dist/index.cjs +2696 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1686 -0
- package/dist/index.d.ts +1686 -0
- package/dist/index.js +2609 -0
- package/dist/index.js.map +1 -0
- package/package.json +68 -0
- package/rpc-schema.json +205 -0
- package/rpc.json +169 -0
package/README.md
ADDED
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
# Unified TON Provider System
|
|
2
|
+
|
|
3
|
+
A bullet-proof TON RPC provider management system for multi-project use.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Multi-provider support** with automatic failover
|
|
8
|
+
- **Health checking** with latency and block height monitoring
|
|
9
|
+
- **Token bucket rate limiting** per provider
|
|
10
|
+
- **Automatic best provider selection** based on health, latency, and priority
|
|
11
|
+
- **Custom endpoint override** for testing
|
|
12
|
+
- **Environment-based configuration** via `.env` file
|
|
13
|
+
- **Cross-platform** - works in Node.js and Browser environments
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
### NPM Package
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Using npm
|
|
21
|
+
npm install ton-provider-system
|
|
22
|
+
|
|
23
|
+
# Using pnpm
|
|
24
|
+
pnpm add ton-provider-system
|
|
25
|
+
|
|
26
|
+
# Using yarn
|
|
27
|
+
yarn add ton-provider-system
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Peer Dependencies
|
|
31
|
+
|
|
32
|
+
This package requires the following peer dependencies (you must install them in your project):
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pnpm add @ton/core @ton/ton @orbs-network/ton-access
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Or add to your `package.json`:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"ton-provider-system": "^0.1.0",
|
|
44
|
+
"@orbs-network/ton-access": "^2.3.0",
|
|
45
|
+
"@ton/core": "^0.59.0",
|
|
46
|
+
"@ton/ton": "^15.0.0"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Quick Start
|
|
52
|
+
|
|
53
|
+
### Node.js (Scripts, Telegram Bot)
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { ProviderManager, getTonClient } from 'ton-provider-system';
|
|
57
|
+
|
|
58
|
+
// Initialize
|
|
59
|
+
const pm = ProviderManager.getInstance();
|
|
60
|
+
await pm.init('testnet');
|
|
61
|
+
|
|
62
|
+
// Get TonClient for blockchain operations
|
|
63
|
+
const client = await getTonClient(pm);
|
|
64
|
+
|
|
65
|
+
// Use the client
|
|
66
|
+
const balance = await client.getBalance(address);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Browser (React/Next.js)
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { ProviderManager, BrowserAdapter } from 'ton-provider-system';
|
|
73
|
+
|
|
74
|
+
// Create instance (not singleton for React)
|
|
75
|
+
const pm = new ProviderManager({ adapter: 'browser' });
|
|
76
|
+
await pm.init(network);
|
|
77
|
+
|
|
78
|
+
// Use browser adapter for fetch-based operations
|
|
79
|
+
const adapter = new BrowserAdapter(pm);
|
|
80
|
+
const balance = await adapter.getAddressBalance(address);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Configuration
|
|
84
|
+
|
|
85
|
+
### Provider Definitions
|
|
86
|
+
|
|
87
|
+
The package includes default provider definitions in `rpc.json` (bundled with the package).
|
|
88
|
+
This file contains:
|
|
89
|
+
- Provider endpoints with `{key}` placeholders
|
|
90
|
+
- Environment variable names for API keys
|
|
91
|
+
- RPS limits and priorities
|
|
92
|
+
- Default provider order per network
|
|
93
|
+
|
|
94
|
+
The JSON Schema (`rpc-schema.json`) provides validation and IDE autocomplete.
|
|
95
|
+
|
|
96
|
+
**Note**: The default `rpc.json` is included in the package. You can override it by providing a custom path when creating the registry.
|
|
97
|
+
|
|
98
|
+
### Environment Variables
|
|
99
|
+
|
|
100
|
+
Set API keys in your `.env` file. See `env.example` for a complete template.
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# TON Center (10 RPS with API key, 1 RPS without)
|
|
104
|
+
TONCENTER_API_KEY=your-toncenter-api-key
|
|
105
|
+
|
|
106
|
+
# Chainstack (25 RPS) - extract key from URL
|
|
107
|
+
# URL: https://ton-testnet.core.chainstack.com/YOUR_KEY/api/v2
|
|
108
|
+
CHAINSTACK_KEY_TESTNET=your-chainstack-key
|
|
109
|
+
|
|
110
|
+
# QuickNode (15 RPS) - use subdomain from URL
|
|
111
|
+
QUICKNODE_KEY_MAINNET=your-quicknode-subdomain
|
|
112
|
+
|
|
113
|
+
# GetBlock (20 RPS) - use the access token
|
|
114
|
+
GETBLOCK_KEY_MAINNET=your-getblock-token
|
|
115
|
+
|
|
116
|
+
# OnFinality (4 RPS) - use apikey from URL
|
|
117
|
+
ONFINALITY_KEY_TESTNET=your-onfinality-apikey
|
|
118
|
+
|
|
119
|
+
# Tatum (3 RPS) - separate keys for testnet/mainnet
|
|
120
|
+
TATUM_API_KEY_TESTNET=your-tatum-testnet-key
|
|
121
|
+
TATUM_API_KEY_MAINNET=your-tatum-mainnet-key
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The `{key}` placeholder in endpoint URLs is replaced with the env var value.
|
|
125
|
+
|
|
126
|
+
## API Reference
|
|
127
|
+
|
|
128
|
+
### ProviderManager
|
|
129
|
+
|
|
130
|
+
Main entry point for the provider system.
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
// Singleton (recommended for Node.js)
|
|
134
|
+
const pm = ProviderManager.getInstance();
|
|
135
|
+
|
|
136
|
+
// Instance (recommended for Browser/React)
|
|
137
|
+
const pm = new ProviderManager({ adapter: 'browser' });
|
|
138
|
+
|
|
139
|
+
// Initialize for a network
|
|
140
|
+
await pm.init('testnet');
|
|
141
|
+
await pm.init('mainnet');
|
|
142
|
+
|
|
143
|
+
// Get endpoint URL
|
|
144
|
+
const endpoint = await pm.getEndpoint();
|
|
145
|
+
|
|
146
|
+
// Get endpoint with rate limiting
|
|
147
|
+
const endpoint = await pm.getEndpointWithRateLimit(5000);
|
|
148
|
+
|
|
149
|
+
// Test all providers
|
|
150
|
+
const results = await pm.testAllProviders();
|
|
151
|
+
|
|
152
|
+
// Report errors (for automatic failover)
|
|
153
|
+
pm.reportError(error);
|
|
154
|
+
pm.reportSuccess();
|
|
155
|
+
|
|
156
|
+
// Manual provider selection
|
|
157
|
+
pm.setSelectedProvider('chainstack_testnet');
|
|
158
|
+
pm.setAutoSelect(true);
|
|
159
|
+
|
|
160
|
+
// Custom endpoint override
|
|
161
|
+
pm.setCustomEndpoint('https://custom.endpoint/api/v2');
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### NodeAdapter
|
|
165
|
+
|
|
166
|
+
Node.js adapter with TonClient and REST API support.
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { NodeAdapter, getTonClient } from './provider_system';
|
|
170
|
+
|
|
171
|
+
const adapter = new NodeAdapter(pm);
|
|
172
|
+
|
|
173
|
+
// Get TonClient
|
|
174
|
+
const client = await adapter.getClient();
|
|
175
|
+
|
|
176
|
+
// REST API methods
|
|
177
|
+
const state = await adapter.getAddressState(address);
|
|
178
|
+
const balance = await adapter.getAddressBalance(address);
|
|
179
|
+
const result = await adapter.runGetMethod(address, 'get_data', []);
|
|
180
|
+
await adapter.sendBoc(boc);
|
|
181
|
+
const deployed = await adapter.isContractDeployed(address);
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### BrowserAdapter
|
|
185
|
+
|
|
186
|
+
Browser-compatible adapter using fetch.
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
import { BrowserAdapter } from './provider_system';
|
|
190
|
+
|
|
191
|
+
const adapter = new BrowserAdapter(pm);
|
|
192
|
+
|
|
193
|
+
// REST API methods
|
|
194
|
+
const state = await adapter.getAddressState(address);
|
|
195
|
+
const balance = await adapter.getAddressBalance(address);
|
|
196
|
+
const info = await adapter.getAddressInfo(address);
|
|
197
|
+
const result = await adapter.runGetMethod(address, 'get_data', []);
|
|
198
|
+
|
|
199
|
+
// JSON-RPC method
|
|
200
|
+
const data = await adapter.jsonRpc('getMasterchainInfo');
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### HealthChecker
|
|
204
|
+
|
|
205
|
+
Test provider health and connectivity.
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
import { createHealthChecker, createRegistry } from './provider_system';
|
|
209
|
+
|
|
210
|
+
const registry = await createRegistry();
|
|
211
|
+
const healthChecker = createHealthChecker({
|
|
212
|
+
timeoutMs: 10000,
|
|
213
|
+
maxBlocksBehind: 10,
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
// Test single provider
|
|
217
|
+
const result = await healthChecker.testProvider(provider);
|
|
218
|
+
|
|
219
|
+
// Test multiple providers
|
|
220
|
+
const results = await healthChecker.testProviders(providers);
|
|
221
|
+
|
|
222
|
+
// Get best provider
|
|
223
|
+
const best = healthChecker.getBestProvider('testnet');
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### RateLimiterManager
|
|
227
|
+
|
|
228
|
+
Per-provider rate limiting with token bucket algorithm.
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
import { createRateLimiterManager } from './provider_system';
|
|
232
|
+
|
|
233
|
+
const rateLimiter = createRateLimiterManager();
|
|
234
|
+
|
|
235
|
+
// Configure for a provider
|
|
236
|
+
rateLimiter.setConfig('chainstack_testnet', {
|
|
237
|
+
rps: 25,
|
|
238
|
+
burstSize: 30,
|
|
239
|
+
minDelayMs: 40,
|
|
240
|
+
backoffMultiplier: 2,
|
|
241
|
+
maxBackoffMs: 10000,
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Acquire token before making request
|
|
245
|
+
const acquired = await rateLimiter.acquire('chainstack_testnet', 5000);
|
|
246
|
+
if (acquired) {
|
|
247
|
+
// Make request
|
|
248
|
+
rateLimiter.reportSuccess('chainstack_testnet');
|
|
249
|
+
} else {
|
|
250
|
+
// Rate limit timeout
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Report rate limit error
|
|
254
|
+
rateLimiter.reportRateLimitError('chainstack_testnet');
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## File Structure
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
provider_system/
|
|
261
|
+
├── rpc.json # Provider definitions (main config)
|
|
262
|
+
├── rpc-schema.json # JSON Schema for validation
|
|
263
|
+
├── README.md # This file
|
|
264
|
+
├── index.ts # Main exports
|
|
265
|
+
├── types.ts # TypeScript interfaces
|
|
266
|
+
├── config/
|
|
267
|
+
│ ├── schema.ts # Zod schema validation
|
|
268
|
+
│ ├── parser.ts # Config loading and env resolution
|
|
269
|
+
│ └── index.ts # Config exports
|
|
270
|
+
├── core/
|
|
271
|
+
│ ├── registry.ts # Provider registry
|
|
272
|
+
│ ├── healthChecker.ts # Health/latency checks
|
|
273
|
+
│ ├── rateLimiter.ts # Token bucket rate limiter
|
|
274
|
+
│ ├── selector.ts # Best provider selection
|
|
275
|
+
│ ├── manager.ts # Main ProviderManager
|
|
276
|
+
│ └── index.ts # Core exports
|
|
277
|
+
├── adapters/
|
|
278
|
+
│ ├── node.ts # Node.js adapter (TonClient)
|
|
279
|
+
│ ├── browser.ts # Browser adapter (fetch)
|
|
280
|
+
│ └── index.ts # Adapter exports
|
|
281
|
+
├── utils/
|
|
282
|
+
│ ├── endpoint.ts # URL normalization
|
|
283
|
+
│ ├── timeout.ts # Timeout utilities
|
|
284
|
+
│ └── index.ts # Utils exports
|
|
285
|
+
└── test.ts # Test script
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Integration Guide
|
|
289
|
+
|
|
290
|
+
### Node.js Project
|
|
291
|
+
|
|
292
|
+
1. Install the package:
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
pnpm add ton-provider-system @ton/core @ton/ton @orbs-network/ton-access
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
2. Use in your code:
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
import { ProviderManager, getTonClient } from 'ton-provider-system';
|
|
302
|
+
|
|
303
|
+
const pm = ProviderManager.getInstance();
|
|
304
|
+
await pm.init('testnet');
|
|
305
|
+
const client = await getTonClient(pm);
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Next.js/React (Browser)
|
|
309
|
+
|
|
310
|
+
1. Install the package:
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
pnpm add ton-provider-system @ton/core @orbs-network/ton-access
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
2. Use in your React component:
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
import { ProviderManager, BrowserAdapter } from 'ton-provider-system';
|
|
320
|
+
|
|
321
|
+
export function ProviderProvider({ children }) {
|
|
322
|
+
const { network } = useNetwork();
|
|
323
|
+
const [manager] = useState(() => new ProviderManager({ adapter: 'browser' }));
|
|
324
|
+
const [adapter, setAdapter] = useState<BrowserAdapter | null>(null);
|
|
325
|
+
|
|
326
|
+
useEffect(() => {
|
|
327
|
+
manager.init(network).then(() => {
|
|
328
|
+
setAdapter(new BrowserAdapter(manager));
|
|
329
|
+
});
|
|
330
|
+
}, [network, manager]);
|
|
331
|
+
|
|
332
|
+
// ...
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Telegram Bot
|
|
337
|
+
|
|
338
|
+
1. Install the package:
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
pnpm add ton-provider-system @ton/core @ton/ton @orbs-network/ton-access
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
2. Initialize on bot startup:
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
// src/bot.ts
|
|
348
|
+
import { ProviderManager } from 'ton-provider-system';
|
|
349
|
+
|
|
350
|
+
const pm = ProviderManager.getInstance();
|
|
351
|
+
|
|
352
|
+
async function startBot() {
|
|
353
|
+
// Initialize provider system
|
|
354
|
+
await pm.init(getNetwork());
|
|
355
|
+
|
|
356
|
+
// Optionally re-test providers periodically
|
|
357
|
+
setInterval(() => {
|
|
358
|
+
pm.testAllProviders().catch(console.error);
|
|
359
|
+
}, 5 * 60 * 1000); // Every 5 minutes
|
|
360
|
+
|
|
361
|
+
// Start bot
|
|
362
|
+
bot.start();
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
## Development
|
|
367
|
+
|
|
368
|
+
### Building
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
# Build the library
|
|
372
|
+
pnpm build
|
|
373
|
+
|
|
374
|
+
# Watch mode for development
|
|
375
|
+
pnpm dev
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Testing
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
# Run full test suite
|
|
382
|
+
pnpm test
|
|
383
|
+
|
|
384
|
+
# Quick test (skip network tests)
|
|
385
|
+
pnpm test:quick
|
|
386
|
+
|
|
387
|
+
# Verbose test output
|
|
388
|
+
pnpm test:verbose
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
**Note**: Tests require environment variables to be set in `.env` file. See `env.example` for template.
|
|
392
|
+
|
|
393
|
+
## Troubleshooting
|
|
394
|
+
|
|
395
|
+
### No providers available
|
|
396
|
+
|
|
397
|
+
1. Check `.env` file has API keys configured
|
|
398
|
+
2. Run `pnpm check-connection` to test providers
|
|
399
|
+
|
|
400
|
+
### Rate limit errors
|
|
401
|
+
|
|
402
|
+
1. The system automatically switches to next provider on 429 errors
|
|
403
|
+
2. Configure more providers in `.env` for redundancy
|
|
404
|
+
|
|
405
|
+
### Block height mismatch (stale provider)
|
|
406
|
+
|
|
407
|
+
1. Provider is returning old data
|
|
408
|
+
2. System marks it as `stale` and prefers fresh providers
|
|
409
|
+
|
|
410
|
+
## Publishing
|
|
411
|
+
|
|
412
|
+
This package is published to NPM. To publish a new version:
|
|
413
|
+
|
|
414
|
+
1. Update version in `package.json` (follow semver)
|
|
415
|
+
2. Run `pnpm build` to ensure latest code is built
|
|
416
|
+
3. Run `npm pack --dry-run` to verify what will be published
|
|
417
|
+
4. Publish: `npm publish --access public` (if scoped package)
|
|
418
|
+
|
|
419
|
+
## License
|
|
420
|
+
|
|
421
|
+
MIT
|