openttt 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 +391 -0
- package/dist/adaptive_switch.d.ts +44 -0
- package/dist/adaptive_switch.js +108 -0
- package/dist/auto_mint.d.ts +45 -0
- package/dist/auto_mint.js +244 -0
- package/dist/dynamic_fee.d.ts +64 -0
- package/dist/dynamic_fee.js +203 -0
- package/dist/errors.d.ts +45 -0
- package/dist/errors.js +74 -0
- package/dist/evm_connector.d.ts +88 -0
- package/dist/evm_connector.js +297 -0
- package/dist/golay.d.ts +6 -0
- package/dist/golay.js +166 -0
- package/dist/grg_forward.d.ts +6 -0
- package/dist/grg_forward.js +59 -0
- package/dist/grg_inverse.d.ts +7 -0
- package/dist/grg_inverse.js +97 -0
- package/dist/grg_pipeline.d.ts +13 -0
- package/dist/grg_pipeline.js +64 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +38 -0
- package/dist/logger.d.ts +18 -0
- package/dist/logger.js +51 -0
- package/dist/networks.d.ts +13 -0
- package/dist/networks.js +23 -0
- package/dist/pool_registry.d.ts +58 -0
- package/dist/pool_registry.js +129 -0
- package/dist/protocol_fee.d.ts +56 -0
- package/dist/protocol_fee.js +176 -0
- package/dist/reed_solomon.d.ts +12 -0
- package/dist/reed_solomon.js +179 -0
- package/dist/signer.d.ts +76 -0
- package/dist/signer.js +329 -0
- package/dist/time_synthesis.d.ts +49 -0
- package/dist/time_synthesis.js +372 -0
- package/dist/ttt_builder.d.ts +32 -0
- package/dist/ttt_builder.js +84 -0
- package/dist/ttt_client.d.ts +118 -0
- package/dist/ttt_client.js +352 -0
- package/dist/types.d.ts +141 -0
- package/dist/types.js +9 -0
- package/dist/v4_hook.d.ts +43 -0
- package/dist/v4_hook.js +115 -0
- package/dist/x402_enforcer.d.ts +29 -0
- package/dist/x402_enforcer.js +67 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
# OpenTTT
|
|
2
|
+
|
|
3
|
+
**OpenSSL for Transaction Ordering** -- TLS-grade Proof of Time for DeFi.
|
|
4
|
+
|
|
5
|
+
OpenTTT brings cryptographic time verification to blockchain transaction ordering. Where TLS made HTTP trustworthy, OpenTTT makes transaction sequencing verifiable. No trust assumptions. No gentleman's agreements. Physics.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/openttt)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[]()
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
npm install openttt
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Why OpenTTT
|
|
18
|
+
|
|
19
|
+
Current MEV protection relies on **trust**: builders promise fair ordering, protocols ask nicely, and everyone hopes for the best. Flashbots asks builders to behave. OpenTTT proves whether they did.
|
|
20
|
+
|
|
21
|
+
| | Flashbots | OpenTTT |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| **Mechanism** | Social contract (request) | Physical verification (proof) |
|
|
24
|
+
| **Enforcement** | Reputation, exclusion | Economic natural selection |
|
|
25
|
+
| **Bad actors** | Must be identified and removed | Naturally unprofitable, self-selecting out |
|
|
26
|
+
| **Time source** | Block timestamp (miner-controlled) | Multi-source NTP synthesis (NIST, KRISS, Google) |
|
|
27
|
+
|
|
28
|
+
**The core insight**: Rollups generate precise timestamps and deliver them to builders with a receipt. The Adaptive GRG pipeline then verifies whether the builder respected that ordering:
|
|
29
|
+
|
|
30
|
+
- **Honest builder**: Sequence matches -> **Turbo mode** (50ms verification) -> faster -> more profitable
|
|
31
|
+
- **Dishonest builder**: Sequence mismatch -> **Full mode** (127ms verification) -> slower -> less profitable -> leaves
|
|
32
|
+
|
|
33
|
+
No governance vote. No slashing committee. Cheating is simply bad business.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
Three lines to start minting TimeTokens:
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import { TTTClient } from "openttt";
|
|
43
|
+
|
|
44
|
+
const ttt = await TTTClient.forBase({
|
|
45
|
+
signer: { type: "privateKey", envVar: "OPERATOR_PK" },
|
|
46
|
+
});
|
|
47
|
+
ttt.startAutoMint();
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
That is it. The SDK connects to Base Mainnet, synthesizes time from three atomic clock sources, and begins minting Proof-of-Time tokens at your configured tier interval.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Progressive Disclosure
|
|
55
|
+
|
|
56
|
+
OpenTTT is designed around progressive disclosure. Start simple, add control as you need it.
|
|
57
|
+
|
|
58
|
+
### Level 1 -- Just Works
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { TTTClient } from "openttt";
|
|
62
|
+
|
|
63
|
+
const ttt = await TTTClient.forBase({
|
|
64
|
+
signer: { type: "privateKey", envVar: "OPERATOR_PK" },
|
|
65
|
+
});
|
|
66
|
+
ttt.startAutoMint();
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Level 2 -- Custom Network and Tier
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
const ttt = await TTTClient.forSepolia({
|
|
73
|
+
signer: { type: "privateKey", key: process.env.OPERATOR_PK! },
|
|
74
|
+
rpcUrl: "https://my-rpc.example.com",
|
|
75
|
+
tier: "T2_slot",
|
|
76
|
+
});
|
|
77
|
+
ttt.startAutoMint();
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Level 3 -- Full Control
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
const ttt = await TTTClient.create({
|
|
84
|
+
signer: {
|
|
85
|
+
type: "turnkey",
|
|
86
|
+
apiBaseUrl: "https://api.turnkey.com",
|
|
87
|
+
organizationId: "org-...",
|
|
88
|
+
privateKeyId: "pk-...",
|
|
89
|
+
apiPublicKey: "...",
|
|
90
|
+
apiPrivateKey: "...",
|
|
91
|
+
},
|
|
92
|
+
network: "base",
|
|
93
|
+
tier: "T1_block",
|
|
94
|
+
contractAddress: "0x...",
|
|
95
|
+
poolAddress: "0x...",
|
|
96
|
+
timeSources: ["nist", "kriss", "google"],
|
|
97
|
+
protocolFeeRate: 0.05,
|
|
98
|
+
enableGracefulShutdown: true,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
ttt.startAutoMint();
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Signer Options
|
|
107
|
+
|
|
108
|
+
OpenTTT abstracts away signer complexity. Use a raw private key for development, TEE-backed keys for production, or cloud HSMs for institutional deployments.
|
|
109
|
+
|
|
110
|
+
| Type | Use Case | Config |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| `privateKey` | Development, small operators | `{ type: "privateKey", key: "0x..." }` or `{ type: "privateKey", envVar: "OPERATOR_PK" }` |
|
|
113
|
+
| `turnkey` | Production, TEE-backed institutional custody | `{ type: "turnkey", apiBaseUrl, organizationId, privateKeyId, apiPublicKey, apiPrivateKey }` |
|
|
114
|
+
| `privy` | Embedded wallets, consumer-facing apps | `{ type: "privy", appId, appSecret }` |
|
|
115
|
+
| `kms` | Cloud HSM (AWS KMS or GCP Cloud KMS) | `{ type: "kms", provider: "aws"\|"gcp", keyId, ... }` |
|
|
116
|
+
|
|
117
|
+
**AWS KMS** requires `@aws-sdk/client-kms`. **GCP KMS** requires `@google-cloud/kms`. Both are optional peer dependencies -- install only what you use.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Tiers
|
|
122
|
+
|
|
123
|
+
Tiers control the minting interval. Choose based on your protocol's ordering resolution requirements.
|
|
124
|
+
|
|
125
|
+
| Tier | Interval | Use Case |
|
|
126
|
+
|---|---|---|
|
|
127
|
+
| `T0_epoch` | 6.4 minutes | Epoch-level ordering (validator sets, beacon chain) |
|
|
128
|
+
| `T1_block` | 2 seconds | Block-level ordering on Base L2 **(default)** |
|
|
129
|
+
| `T2_slot` | 12 seconds | Slot-level ordering on Ethereum L1 |
|
|
130
|
+
| `T3_micro` | 100 milliseconds | High-frequency ordering (IoT, sub-block) |
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
const ttt = await TTTClient.forBase({
|
|
134
|
+
signer: { type: "privateKey", envVar: "OPERATOR_PK" },
|
|
135
|
+
tier: "T2_slot",
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Health Monitoring
|
|
142
|
+
|
|
143
|
+
Production deployments need observability. `getHealth()` returns a comprehensive status object covering connectivity, balance, and mint performance.
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
const health = await ttt.getHealth();
|
|
147
|
+
|
|
148
|
+
console.log(health);
|
|
149
|
+
// {
|
|
150
|
+
// healthy: true,
|
|
151
|
+
// checks: {
|
|
152
|
+
// initialized: true,
|
|
153
|
+
// rpcConnected: true,
|
|
154
|
+
// signerAvailable: true,
|
|
155
|
+
// balanceSufficient: true,
|
|
156
|
+
// ntpSourcesOk: true
|
|
157
|
+
// },
|
|
158
|
+
// metrics: {
|
|
159
|
+
// mintCount: 142,
|
|
160
|
+
// mintFailures: 0,
|
|
161
|
+
// successRate: 1.0,
|
|
162
|
+
// totalFeesPaid: "71000000000000",
|
|
163
|
+
// avgMintLatencyMs: 1847,
|
|
164
|
+
// lastMintAt: "2026-03-14T10:30:00.000Z",
|
|
165
|
+
// uptimeMs: 86400000
|
|
166
|
+
// },
|
|
167
|
+
// alerts: []
|
|
168
|
+
// }
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Alerts** are emitted automatically when:
|
|
172
|
+
- RPC connection is lost
|
|
173
|
+
- ETH balance drops below threshold (default: 0.01 ETH)
|
|
174
|
+
- Mint success rate falls below 80%
|
|
175
|
+
|
|
176
|
+
Register a callback for real-time alerting:
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
ttt.onAlert((alert) => {
|
|
180
|
+
// Send to PagerDuty, Slack, Telegram, etc.
|
|
181
|
+
console.error(`[OpenTTT Alert] ${alert}`);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
ttt.setMinBalance(ethers.parseEther("0.05")); // Custom threshold
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Networks
|
|
190
|
+
|
|
191
|
+
| Network | Chain ID | Factory Method |
|
|
192
|
+
|---|---|---|
|
|
193
|
+
| Base Mainnet | 8453 | `TTTClient.forBase(config)` |
|
|
194
|
+
| Base Sepolia | 84532 | `TTTClient.forSepolia(config)` |
|
|
195
|
+
|
|
196
|
+
Custom networks can be provided via the `network` field in `TTTClient.create()`:
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
const ttt = await TTTClient.create({
|
|
200
|
+
signer: { type: "privateKey", envVar: "OPERATOR_PK" },
|
|
201
|
+
network: {
|
|
202
|
+
chainId: 8453,
|
|
203
|
+
rpcUrl: "https://my-custom-rpc.example.com",
|
|
204
|
+
tttAddress: "0x...",
|
|
205
|
+
protocolFeeAddress: "0x...",
|
|
206
|
+
usdcAddress: "0x...",
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## API Reference
|
|
214
|
+
|
|
215
|
+
### TTTClient
|
|
216
|
+
|
|
217
|
+
| Method | Description |
|
|
218
|
+
|---|---|
|
|
219
|
+
| `TTTClient.create(config)` | Create and initialize a client with full configuration |
|
|
220
|
+
| `TTTClient.forBase(config)` | Factory for Base Mainnet (chain ID 8453) |
|
|
221
|
+
| `TTTClient.forSepolia(config)` | Factory for Base Sepolia testnet (chain ID 84532) |
|
|
222
|
+
| `ttt.startAutoMint()` | Start automatic TimeToken minting at the configured tier interval |
|
|
223
|
+
| `ttt.stopAutoMint()` | Stop the auto-mint loop |
|
|
224
|
+
| `ttt.getHealth()` | Returns `HealthStatus` with connectivity, balance, and performance checks |
|
|
225
|
+
| `ttt.getStatus()` | Returns current tier, mint count, fees paid, and token balances |
|
|
226
|
+
| `ttt.listPools()` | List all registered pool addresses |
|
|
227
|
+
| `ttt.getPoolStats(address)` | Get mint/burn statistics for a specific pool |
|
|
228
|
+
| `ttt.onAlert(callback)` | Register a callback for health alerts |
|
|
229
|
+
| `ttt.setMinBalance(wei)` | Set minimum ETH balance threshold for alerts |
|
|
230
|
+
| `ttt.destroy()` | Gracefully shut down: stops minting, unsubscribes events, clears state |
|
|
231
|
+
|
|
232
|
+
### TimeSynthesis
|
|
233
|
+
|
|
234
|
+
| Method | Description |
|
|
235
|
+
|---|---|
|
|
236
|
+
| `synthesize()` | Query all configured NTP sources and return a median-synthesized timestamp |
|
|
237
|
+
| `generateProofOfTime()` | Generate a verifiable Proof of Time with source signatures |
|
|
238
|
+
| `verifyProofOfTime(pot)` | Verify that all source readings are within tolerance of the median |
|
|
239
|
+
| `TimeSynthesis.getOnChainHash(pot)` | Keccak256 hash of a PoT for on-chain submission |
|
|
240
|
+
| `TimeSynthesis.serializeToBinary(pot)` | Compact binary serialization for network transport |
|
|
241
|
+
| `TimeSynthesis.deserializeFromBinary(buf)` | Deserialize from binary format |
|
|
242
|
+
|
|
243
|
+
### GrgPipeline
|
|
244
|
+
|
|
245
|
+
| Method | Description |
|
|
246
|
+
|---|---|
|
|
247
|
+
| `GrgPipeline.processForward(data)` | Encode: Golomb compression -> Reed-Solomon erasure coding -> Golay verification |
|
|
248
|
+
| `GrgPipeline.processInverse(shards, length)` | Decode: Golay verify -> Reed-Solomon reconstruct -> Golomb decompress |
|
|
249
|
+
|
|
250
|
+
### AdaptiveSwitch
|
|
251
|
+
|
|
252
|
+
| Method | Description |
|
|
253
|
+
|---|---|
|
|
254
|
+
| `verifyBlock(block, tttRecord)` | Verify block ordering against TTT record; returns `TURBO` or `FULL` mode |
|
|
255
|
+
| `getCurrentMode()` | Current adaptive mode |
|
|
256
|
+
| `getFeeDiscount()` | Fee discount for current mode (20% in TURBO, 0% in FULL) |
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Architecture
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
TTTClient (entry point)
|
|
264
|
+
|-- AutoMintEngine Periodic minting loop
|
|
265
|
+
| |-- TimeSynthesis NTP multi-source median synthesis (NIST, KRISS, Google)
|
|
266
|
+
| |-- DynamicFeeEngine Oracle-based pricing
|
|
267
|
+
| |-- EVMConnector On-chain mint/burn/events (ethers v6)
|
|
268
|
+
| '-- ProtocolFee EIP-712 signed fee collection
|
|
269
|
+
|-- AdaptiveSwitch TURBO/FULL mode state machine
|
|
270
|
+
|-- GRG Pipeline Golomb + Reed-Solomon + Golay error correction
|
|
271
|
+
|-- PoolRegistry Multi-pool statistics tracking
|
|
272
|
+
'-- Signer Abstraction PrivateKey | Turnkey | Privy | KMS
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### The GRG Pipeline
|
|
276
|
+
|
|
277
|
+
GRG (Golomb-Reed-Golay) is the data integrity backbone of OpenTTT, analogous to how the TLS record protocol protects HTTP payloads.
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
FORWARD (Encode)
|
|
281
|
+
Raw Data --> Golomb-Rice Compression
|
|
282
|
+
--> Reed-Solomon Erasure Coding
|
|
283
|
+
--> Golay(24,12) Verification Codes
|
|
284
|
+
--> Shards
|
|
285
|
+
|
|
286
|
+
INVERSE (Decode)
|
|
287
|
+
Shards --> Golay(24,12) Error Detection
|
|
288
|
+
--> Reed-Solomon Reconstruction
|
|
289
|
+
--> Golomb-Rice Decompression
|
|
290
|
+
--> Raw Data
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
**Golomb-Rice** compresses timestamp deltas efficiently (small integers compress well).
|
|
294
|
+
**Reed-Solomon** adds erasure coding so data survives shard loss.
|
|
295
|
+
**Golay(24,12)** detects and corrects up to 3-bit errors per 24-bit codeword.
|
|
296
|
+
|
|
297
|
+
### Adaptive Mode Switching
|
|
298
|
+
|
|
299
|
+
The economic enforcement mechanism uses a sliding window (20 blocks) with hysteresis:
|
|
300
|
+
|
|
301
|
+
- **Entry to Turbo**: 95% ordering match rate over 20+ blocks
|
|
302
|
+
- **Maintain Turbo**: 85% match rate (relaxed to prevent flapping)
|
|
303
|
+
- **Integrity failure in Turbo**: Exponential backoff penalty (20, 40, 80, 160, 320 blocks)
|
|
304
|
+
|
|
305
|
+
This asymmetry is deliberate: it is hard to earn trust and easy to lose it.
|
|
306
|
+
|
|
307
|
+
### Time Synthesis
|
|
308
|
+
|
|
309
|
+
OpenTTT queries multiple atomic clock-synchronized NTP sources in parallel and produces a median-synthesized timestamp with confidence scoring:
|
|
310
|
+
|
|
311
|
+
- **NIST** (time.nist.gov) -- US national standard
|
|
312
|
+
- **KRISS** (time.kriss.re.kr) -- Korean national standard
|
|
313
|
+
- **Google** (time.google.com) -- Leap-smeared public NTP
|
|
314
|
+
|
|
315
|
+
All readings must fall within 100ms tolerance of the synthesized median, or the Proof of Time is rejected. Single-source operation triggers a degraded-confidence warning.
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## Error Handling
|
|
320
|
+
|
|
321
|
+
All SDK errors extend `TTTBaseError` and include three fields for actionable diagnostics:
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
import { TTTSignerError } from "openttt";
|
|
325
|
+
|
|
326
|
+
try {
|
|
327
|
+
const ttt = await TTTClient.forBase({
|
|
328
|
+
signer: { type: "privateKey", envVar: "MISSING_VAR" },
|
|
329
|
+
});
|
|
330
|
+
} catch (e) {
|
|
331
|
+
if (e instanceof TTTSignerError) {
|
|
332
|
+
console.error(e.message); // What happened
|
|
333
|
+
console.error(e.reason); // Why it happened
|
|
334
|
+
console.error(e.fix); // How to fix it
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
| Error Class | Scope |
|
|
340
|
+
|---|---|
|
|
341
|
+
| `TTTConfigError` | SDK or engine configuration |
|
|
342
|
+
| `TTTSignerError` | Signer acquisition or usage |
|
|
343
|
+
| `TTTNetworkError` | RPC, chain ID, connectivity |
|
|
344
|
+
| `TTTContractError` | Smart contract interaction |
|
|
345
|
+
| `TTTTimeSynthesisError` | NTP time synthesis failures |
|
|
346
|
+
| `TTTFeeError` | Dynamic fee or protocol fee collection |
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## Graceful Shutdown
|
|
351
|
+
|
|
352
|
+
For long-running services, enable graceful shutdown to cleanly stop minting and release resources on SIGINT:
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
const ttt = await TTTClient.create({
|
|
356
|
+
signer: { type: "privateKey", envVar: "OPERATOR_PK" },
|
|
357
|
+
network: "base",
|
|
358
|
+
enableGracefulShutdown: true,
|
|
359
|
+
});
|
|
360
|
+
ttt.startAutoMint();
|
|
361
|
+
|
|
362
|
+
// Or shut down manually at any time:
|
|
363
|
+
await ttt.destroy();
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## Requirements
|
|
369
|
+
|
|
370
|
+
- Node.js >= 18
|
|
371
|
+
- TypeScript >= 5.3 (for development)
|
|
372
|
+
- Network access to NTP servers (UDP port 123 outbound)
|
|
373
|
+
|
|
374
|
+
**Optional peer dependencies** (install only what you use):
|
|
375
|
+
|
|
376
|
+
| Package | Required for |
|
|
377
|
+
|---|---|
|
|
378
|
+
| `@aws-sdk/client-kms` | AWS KMS signer |
|
|
379
|
+
| `@google-cloud/kms` | GCP Cloud KMS signer |
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## License
|
|
384
|
+
|
|
385
|
+
[Business Source License 1.1](LICENSE)
|
|
386
|
+
|
|
387
|
+
Copyright 2026 Helm Protocol.
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
[GitHub](https://github.com/Helm-Protocol/OpenTTT) | Built by [Helm Protocol](https://github.com/Helm-Protocol)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export declare enum AdaptiveMode {
|
|
2
|
+
TURBO = "TURBO",// 50ms — Valid sequence, low latency
|
|
3
|
+
FULL = "FULL"
|
|
4
|
+
}
|
|
5
|
+
export interface TTTRecord {
|
|
6
|
+
time: number;
|
|
7
|
+
txOrder: string[];
|
|
8
|
+
grgPayload: Uint8Array[];
|
|
9
|
+
}
|
|
10
|
+
export interface Block {
|
|
11
|
+
timestamp: number;
|
|
12
|
+
txs: string[];
|
|
13
|
+
data: Uint8Array;
|
|
14
|
+
}
|
|
15
|
+
export declare class AdaptiveSwitch {
|
|
16
|
+
private windowSize;
|
|
17
|
+
private threshold;
|
|
18
|
+
private history;
|
|
19
|
+
private currentMode;
|
|
20
|
+
private minBlocks;
|
|
21
|
+
private penaltyCooldown;
|
|
22
|
+
private consecutiveFailures;
|
|
23
|
+
private turboEntryThreshold;
|
|
24
|
+
private turboMaintainThreshold;
|
|
25
|
+
/**
|
|
26
|
+
* TTT의 핵심 메커니즘: 타임스탬프 순서 일치율에 따른 Turbo/Full 모드 전환
|
|
27
|
+
*/
|
|
28
|
+
verifyBlock(block: Block, tttRecord: TTTRecord): AdaptiveMode;
|
|
29
|
+
/**
|
|
30
|
+
* 모드에 따른 수수료 할인율 반환
|
|
31
|
+
* TURBO: 20% 할인 (수익 증가 유도)
|
|
32
|
+
* FULL: 할인 없음
|
|
33
|
+
*/
|
|
34
|
+
getFeeDiscount(): number;
|
|
35
|
+
/**
|
|
36
|
+
* 현재 모드 조회
|
|
37
|
+
*/
|
|
38
|
+
getCurrentMode(): AdaptiveMode;
|
|
39
|
+
/**
|
|
40
|
+
* 테스트용: 이력 초기화
|
|
41
|
+
*/
|
|
42
|
+
reset(): void;
|
|
43
|
+
private compareTransactionOrder;
|
|
44
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// sdk/src/adaptive_switch.ts — Adaptive Mode Switcher
|
|
3
|
+
// Turbo (50ms) vs Full (127ms)
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.AdaptiveSwitch = exports.AdaptiveMode = void 0;
|
|
6
|
+
const grg_inverse_1 = require("./grg_inverse");
|
|
7
|
+
const logger_1 = require("./logger");
|
|
8
|
+
var AdaptiveMode;
|
|
9
|
+
(function (AdaptiveMode) {
|
|
10
|
+
AdaptiveMode["TURBO"] = "TURBO";
|
|
11
|
+
AdaptiveMode["FULL"] = "FULL";
|
|
12
|
+
})(AdaptiveMode || (exports.AdaptiveMode = AdaptiveMode = {}));
|
|
13
|
+
const TOLERANCE = 100; // 100ms tolerance for KTSat sync
|
|
14
|
+
class AdaptiveSwitch {
|
|
15
|
+
windowSize = 20; // B1-9: Updated from 10 to 20
|
|
16
|
+
threshold = 0.9; // B1-9: Updated from 0.8 to 0.9
|
|
17
|
+
history = [];
|
|
18
|
+
currentMode = AdaptiveMode.FULL;
|
|
19
|
+
minBlocks = 20; // B1-9: Minimum blocks for TURBO transition
|
|
20
|
+
penaltyCooldown = 0; // B1-9: Penalty cooldown (P2-1: increased to 20 + exponential backoff)
|
|
21
|
+
consecutiveFailures = 0; // P2-1: Track consecutive failures for exponential backoff
|
|
22
|
+
turboEntryThreshold = 0.95; // P2-2: Hysteresis — stricter entry
|
|
23
|
+
turboMaintainThreshold = 0.85; // P2-2: Hysteresis — relaxed maintenance
|
|
24
|
+
/**
|
|
25
|
+
* TTT의 핵심 메커니즘: 타임스탬프 순서 일치율에 따른 Turbo/Full 모드 전환
|
|
26
|
+
*/
|
|
27
|
+
verifyBlock(block, tttRecord) {
|
|
28
|
+
// 1. 타임스탬프 순서 및 시간 일치 여부 확인
|
|
29
|
+
const orderMatch = this.compareTransactionOrder(block.txs, tttRecord.txOrder);
|
|
30
|
+
const timeMatch = Math.abs(block.timestamp - tttRecord.time) < TOLERANCE;
|
|
31
|
+
let sequenceOk = orderMatch && timeMatch;
|
|
32
|
+
// B1-1: Do not skip GrgInverse.verify() in TURBO mode
|
|
33
|
+
// We check integrity regardless of mode
|
|
34
|
+
const integrityOk = grg_inverse_1.GrgInverse.verify(block.data, tttRecord.grgPayload);
|
|
35
|
+
if (!integrityOk) {
|
|
36
|
+
logger_1.logger.error(`[AdaptiveSwitch] GRG integrity check FAILED`);
|
|
37
|
+
sequenceOk = false; // Mark as false if integrity fails
|
|
38
|
+
if (this.currentMode === AdaptiveMode.TURBO) {
|
|
39
|
+
logger_1.logger.warn(`[AdaptiveSwitch] TURBO integrity failure: Penalty cooldown applied`);
|
|
40
|
+
// P2-1: Exponential backoff — 20 * 2^(consecutiveFailures), capped at 320
|
|
41
|
+
this.consecutiveFailures = Math.min(this.consecutiveFailures + 1, 4);
|
|
42
|
+
this.penaltyCooldown = 20 * Math.pow(2, this.consecutiveFailures - 1); // 20, 40, 80, 160, 320
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// 2. 이력 업데이트 (Sliding Window)
|
|
46
|
+
this.history.push(sequenceOk);
|
|
47
|
+
if (this.history.length > this.windowSize) {
|
|
48
|
+
this.history.shift();
|
|
49
|
+
}
|
|
50
|
+
if (this.penaltyCooldown > 0) {
|
|
51
|
+
this.penaltyCooldown--;
|
|
52
|
+
}
|
|
53
|
+
// 3. 일치율 계산 및 모드 전환
|
|
54
|
+
const matchCount = this.history.filter(h => h).length;
|
|
55
|
+
const matchRate = this.history.length > 0 ? matchCount / this.history.length : 0;
|
|
56
|
+
// P2-2: Hysteresis — different thresholds for entering vs maintaining TURBO
|
|
57
|
+
const effectiveThreshold = this.currentMode === AdaptiveMode.TURBO
|
|
58
|
+
? this.turboMaintainThreshold // 85% to stay in TURBO
|
|
59
|
+
: this.turboEntryThreshold; // 95% to enter TURBO
|
|
60
|
+
if (this.history.length >= this.minBlocks && matchRate >= effectiveThreshold && this.penaltyCooldown === 0) {
|
|
61
|
+
if (this.currentMode === AdaptiveMode.FULL) {
|
|
62
|
+
logger_1.logger.info(`[AdaptiveSwitch] Switching to TURBO mode (Match rate: ${(matchRate * 100).toFixed(1)}%, Entry threshold: ${(this.turboEntryThreshold * 100).toFixed(0)}%)`);
|
|
63
|
+
}
|
|
64
|
+
this.currentMode = AdaptiveMode.TURBO;
|
|
65
|
+
this.consecutiveFailures = 0; // P2-1: Reset on successful TURBO
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
if (this.currentMode === AdaptiveMode.TURBO) {
|
|
69
|
+
logger_1.logger.warn(`[AdaptiveSwitch] Switching to FULL mode (Match rate: ${(matchRate * 100).toFixed(1)}%, Maintain threshold: ${(this.turboMaintainThreshold * 100).toFixed(0)}%, Cooldown: ${this.penaltyCooldown})`);
|
|
70
|
+
}
|
|
71
|
+
this.currentMode = AdaptiveMode.FULL;
|
|
72
|
+
}
|
|
73
|
+
return this.currentMode;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 모드에 따른 수수료 할인율 반환
|
|
77
|
+
* TURBO: 20% 할인 (수익 증가 유도)
|
|
78
|
+
* FULL: 할인 없음
|
|
79
|
+
*/
|
|
80
|
+
getFeeDiscount() {
|
|
81
|
+
return this.currentMode === AdaptiveMode.TURBO ? 0.2 : 0.0;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 현재 모드 조회
|
|
85
|
+
*/
|
|
86
|
+
getCurrentMode() {
|
|
87
|
+
return this.currentMode;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* 테스트용: 이력 초기화
|
|
91
|
+
*/
|
|
92
|
+
reset() {
|
|
93
|
+
this.history = [];
|
|
94
|
+
this.currentMode = AdaptiveMode.FULL;
|
|
95
|
+
this.penaltyCooldown = 0;
|
|
96
|
+
this.consecutiveFailures = 0;
|
|
97
|
+
}
|
|
98
|
+
compareTransactionOrder(blockTxs, expectedOrder) {
|
|
99
|
+
if (blockTxs.length !== expectedOrder.length)
|
|
100
|
+
return false;
|
|
101
|
+
for (let i = 0; i < blockTxs.length; i++) {
|
|
102
|
+
if (blockTxs[i] !== expectedOrder[i])
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
exports.AdaptiveSwitch = AdaptiveSwitch;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { EVMConnector } from "./evm_connector";
|
|
2
|
+
import { AutoMintConfig, MintResult } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* AutoMintEngine - TTT 자동 민팅 엔진
|
|
5
|
+
* 시간 합성, 동적 수수료 계산, EVM 민팅을 하나의 루프로 결합
|
|
6
|
+
*/
|
|
7
|
+
export declare class AutoMintEngine {
|
|
8
|
+
private config;
|
|
9
|
+
private timeSynthesis;
|
|
10
|
+
private feeEngine;
|
|
11
|
+
private evmConnector;
|
|
12
|
+
private feeCollector;
|
|
13
|
+
private timer;
|
|
14
|
+
private isRunning;
|
|
15
|
+
private isProcessing;
|
|
16
|
+
private onMintCallback?;
|
|
17
|
+
private onFailureCallback?;
|
|
18
|
+
private onLatencyCallback?;
|
|
19
|
+
private cachedSigner;
|
|
20
|
+
private consecutiveFailures;
|
|
21
|
+
private maxConsecutiveFailures;
|
|
22
|
+
constructor(config: AutoMintConfig);
|
|
23
|
+
getEvmConnector(): EVMConnector;
|
|
24
|
+
setOnMint(callback: (result: MintResult) => void): void;
|
|
25
|
+
setOnFailure(callback: (error: Error) => void): void;
|
|
26
|
+
setOnLatency(callback: (ms: number) => void): void;
|
|
27
|
+
/**
|
|
28
|
+
* 엔진 초기화 (RPC 연결 및 컨트랙트 설정)
|
|
29
|
+
*/
|
|
30
|
+
initialize(): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* 자동 민팅 루프 시작
|
|
33
|
+
*/
|
|
34
|
+
start(): void;
|
|
35
|
+
/**
|
|
36
|
+
* 자동 민팅 루프 정지
|
|
37
|
+
*/
|
|
38
|
+
stop(): void;
|
|
39
|
+
/**
|
|
40
|
+
* 단일 민트 틱 실행
|
|
41
|
+
* 시간합성 → tokenId 생성 → EVM mint 호출 → 수수료 계산/차감
|
|
42
|
+
*/
|
|
43
|
+
mintTick(): Promise<void>;
|
|
44
|
+
private signFeeMessage;
|
|
45
|
+
}
|