openttt 0.2.6 → 0.2.8
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/LICENSE +1 -1
- package/README.md +25 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/osnma_source.d.ts +82 -0
- package/dist/osnma_source.js +169 -0
- package/dist/time_synthesis.d.ts +1 -1
- package/dist/time_synthesis.js +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +47 -3
- package/dist/adaptive_switch.d.ts +0 -59
- package/dist/adaptive_switch.js +0 -145
- package/dist/auto_mint.d.ts +0 -61
- package/dist/auto_mint.js +0 -330
- package/dist/golay.d.ts +0 -7
- package/dist/golay.js +0 -139
- package/dist/grg_forward.d.ts +0 -7
- package/dist/grg_forward.js +0 -68
- package/dist/grg_inverse.d.ts +0 -7
- package/dist/grg_inverse.js +0 -93
- package/dist/grg_pipeline.d.ts +0 -5
- package/dist/grg_pipeline.js +0 -55
- package/dist/reed_solomon.d.ts +0 -13
- package/dist/reed_solomon.js +0 -170
package/LICENSE
CHANGED
|
@@ -3,7 +3,7 @@ Business Source License 1.1
|
|
|
3
3
|
Parameters
|
|
4
4
|
|
|
5
5
|
Licensor: Helm Protocol Foundation
|
|
6
|
-
Licensed Work:
|
|
6
|
+
Licensed Work: TlsTimeToken SDK v0.1.0 (OpenTTT)
|
|
7
7
|
Additional Use
|
|
8
8
|
Grant: Non-production evaluation and testing.
|
|
9
9
|
Change Date: March 14, 2030
|
package/README.md
CHANGED
|
@@ -40,6 +40,31 @@ No governance vote. No slashing committee. Cheating is simply bad business.
|
|
|
40
40
|
|
|
41
41
|
---
|
|
42
42
|
|
|
43
|
+
## Why OpenTTT, not Google Roughtime?
|
|
44
|
+
|
|
45
|
+
A common question: *"Google Roughtime already solves timestamp verification — why do we need OpenTTT?"*
|
|
46
|
+
|
|
47
|
+
The answer: **Roughtime and OpenTTT operate at completely different points in the lifecycle.**
|
|
48
|
+
|
|
49
|
+
| | Google Roughtime | OpenTTT |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| **When it acts** | After block finalization | Before fork transition is applied |
|
|
52
|
+
| **What it does** | Cryptographically proves a timestamp was wrong *after the fact* | Rejects the block *before* it enters chain state |
|
|
53
|
+
| **Enforcement** | Audit trail only — the bad block is already finalized | Block is invalid on nodes running the hook |
|
|
54
|
+
| **Economic effect** | None — requires social/legal follow-up | Validator MEV from timestamp drift → 0 as adoption grows |
|
|
55
|
+
| **Use case** | Security auditing, forensics | Real-time enforcement at ingestion |
|
|
56
|
+
|
|
57
|
+
**In one sentence:**
|
|
58
|
+
> Roughtime proves time fraud happened. OpenTTT makes time fraud economically irrational before it can happen.
|
|
59
|
+
|
|
60
|
+
Roughtime is a valuable audit tool. OpenTTT is an enforcement layer. They are complementary — but only OpenTTT prevents the block from being accepted in the first place.
|
|
61
|
+
|
|
62
|
+
### The game-theoretic guarantee
|
|
63
|
+
|
|
64
|
+
With OpenTTT hooks active on validator nodes, a validator who drifts their timestamp by X seconds to capture MEV will have their block rejected by hook-enabled nodes. As more nodes adopt the hook, the fraction of the network accepting manipulated timestamps shrinks — and so does the MEV available from drift. The economic incentive self-destructs without requiring a slashing condition.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
43
68
|
## Quick Start
|
|
44
69
|
|
|
45
70
|
### Try it in 30 seconds — No ETH, No Wallet
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OSNMA (Galileo Open Service Navigation Message Authentication) Time Source
|
|
3
|
+
*
|
|
4
|
+
* Integrates Galileo OSNMA public key verification into the TTT SDK TimeSource interface.
|
|
5
|
+
* OSNMA provides satellite-grade time authentication via ECDSA P-256/SHA-256.
|
|
6
|
+
*
|
|
7
|
+
* Key data sourced from GSC Europa portal (gsc-europa.eu):
|
|
8
|
+
* - PKID: 2, point: 02219204B5CA6C46B623EEED6CDD2CDDB1F7D6A7532767E5B8DA0DE1EBD695FC99
|
|
9
|
+
* - Merkle Tree root: 7B944FA20915C7931D48DD016D94F9C6381FD37DC6C125D97015272FDDE41393
|
|
10
|
+
* - Hash function: SHA-256, N=16
|
|
11
|
+
* - Applicability: 2025-12-10T10:00:00Z
|
|
12
|
+
*
|
|
13
|
+
* SECURITY MODEL:
|
|
14
|
+
* - Public key is hardcoded from GSC portal (authenticated via EUSPA PKI chain)
|
|
15
|
+
* - Merkle tree root anchors the key — any key change requires new root proof
|
|
16
|
+
* - Stratum is set to 1 (satellite direct, equivalent to GPS timing receiver)
|
|
17
|
+
* - Uncertainty: 50ms base (conservative — actual Galileo timing is ±100ns,
|
|
18
|
+
* but edge SDK without hardware PPS uses NTP-level cross-check)
|
|
19
|
+
*/
|
|
20
|
+
import { TimeReading } from './types';
|
|
21
|
+
import { TimeSource } from './time_synthesis';
|
|
22
|
+
export interface OsnmaKeyMaterial {
|
|
23
|
+
pkid: number;
|
|
24
|
+
publicKeyHex: string;
|
|
25
|
+
merkleRootHex: string;
|
|
26
|
+
hashFunction: string;
|
|
27
|
+
applicabilityMs: number;
|
|
28
|
+
}
|
|
29
|
+
export interface OsnmaVerificationResult {
|
|
30
|
+
valid: boolean;
|
|
31
|
+
pkid: number;
|
|
32
|
+
merkleRootHex: string;
|
|
33
|
+
keyFingerprint: string;
|
|
34
|
+
applicabilityMs: number;
|
|
35
|
+
checkedAt: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Verifies OSNMA key material integrity:
|
|
39
|
+
* 1. Public key point length (compressed P-256 = 33 bytes)
|
|
40
|
+
* 2. Merkle root length (SHA-256 = 32 bytes)
|
|
41
|
+
* 3. Applicability date is in the past (key is active)
|
|
42
|
+
* 4. Computes key fingerprint for audit trail
|
|
43
|
+
*/
|
|
44
|
+
export declare function verifyOsnmaKeyMaterial(key: OsnmaKeyMaterial): OsnmaVerificationResult;
|
|
45
|
+
/**
|
|
46
|
+
* OsnmaTimeSource — implements TimeSource interface for TimeSynthesis integration.
|
|
47
|
+
*
|
|
48
|
+
* In a full hardware integration, this would parse OSNMA navigation messages
|
|
49
|
+
* from a Galileo receiver and verify the TESLA chain + ECDSA signature.
|
|
50
|
+
*
|
|
51
|
+
* In this edge SDK integration:
|
|
52
|
+
* - Key material is verified against the hardcoded GSC anchor
|
|
53
|
+
* - Time is sourced from system clock (same as HTTPS sources)
|
|
54
|
+
* - Stratum is set to 1 to reflect satellite-grade authority
|
|
55
|
+
* - This establishes the OSNMA trust anchor in the SDK trust chain,
|
|
56
|
+
* ready for hardware receiver integration (UART/SPI/USB NMEA feed)
|
|
57
|
+
*/
|
|
58
|
+
export declare class OsnmaTimeSource implements TimeSource {
|
|
59
|
+
readonly name = "osnma";
|
|
60
|
+
private keyMaterial;
|
|
61
|
+
private verificationResult;
|
|
62
|
+
constructor(keyMaterial?: Partial<OsnmaKeyMaterial>);
|
|
63
|
+
/**
|
|
64
|
+
* Verifies key material and returns a TimeReading.
|
|
65
|
+
* Stratum 1 — satellite-grade authority.
|
|
66
|
+
* Uncertainty 50ms — conservative edge estimate without hardware PPS.
|
|
67
|
+
*/
|
|
68
|
+
getTime(): Promise<TimeReading>;
|
|
69
|
+
/**
|
|
70
|
+
* Returns the verified key material for audit/logging.
|
|
71
|
+
*/
|
|
72
|
+
getVerificationResult(): OsnmaVerificationResult | null;
|
|
73
|
+
/**
|
|
74
|
+
* Returns the raw key material (public key hex, merkle root, pkid).
|
|
75
|
+
*/
|
|
76
|
+
getKeyMaterial(): Readonly<OsnmaKeyMaterial>;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Default OSNMA key material from GSC Europa portal.
|
|
80
|
+
* PKID=2, applicable from 2025-12-10T10:00:00Z.
|
|
81
|
+
*/
|
|
82
|
+
export declare const DEFAULT_OSNMA_KEY: OsnmaKeyMaterial;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OSNMA (Galileo Open Service Navigation Message Authentication) Time Source
|
|
4
|
+
*
|
|
5
|
+
* Integrates Galileo OSNMA public key verification into the TTT SDK TimeSource interface.
|
|
6
|
+
* OSNMA provides satellite-grade time authentication via ECDSA P-256/SHA-256.
|
|
7
|
+
*
|
|
8
|
+
* Key data sourced from GSC Europa portal (gsc-europa.eu):
|
|
9
|
+
* - PKID: 2, point: 02219204B5CA6C46B623EEED6CDD2CDDB1F7D6A7532767E5B8DA0DE1EBD695FC99
|
|
10
|
+
* - Merkle Tree root: 7B944FA20915C7931D48DD016D94F9C6381FD37DC6C125D97015272FDDE41393
|
|
11
|
+
* - Hash function: SHA-256, N=16
|
|
12
|
+
* - Applicability: 2025-12-10T10:00:00Z
|
|
13
|
+
*
|
|
14
|
+
* SECURITY MODEL:
|
|
15
|
+
* - Public key is hardcoded from GSC portal (authenticated via EUSPA PKI chain)
|
|
16
|
+
* - Merkle tree root anchors the key — any key change requires new root proof
|
|
17
|
+
* - Stratum is set to 1 (satellite direct, equivalent to GPS timing receiver)
|
|
18
|
+
* - Uncertainty: 50ms base (conservative — actual Galileo timing is ±100ns,
|
|
19
|
+
* but edge SDK without hardware PPS uses NTP-level cross-check)
|
|
20
|
+
*/
|
|
21
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
22
|
+
if (k2 === undefined) k2 = k;
|
|
23
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
24
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
25
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
26
|
+
}
|
|
27
|
+
Object.defineProperty(o, k2, desc);
|
|
28
|
+
}) : (function(o, m, k, k2) {
|
|
29
|
+
if (k2 === undefined) k2 = k;
|
|
30
|
+
o[k2] = m[k];
|
|
31
|
+
}));
|
|
32
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
33
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
34
|
+
}) : function(o, v) {
|
|
35
|
+
o["default"] = v;
|
|
36
|
+
});
|
|
37
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
38
|
+
var ownKeys = function(o) {
|
|
39
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
40
|
+
var ar = [];
|
|
41
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
42
|
+
return ar;
|
|
43
|
+
};
|
|
44
|
+
return ownKeys(o);
|
|
45
|
+
};
|
|
46
|
+
return function (mod) {
|
|
47
|
+
if (mod && mod.__esModule) return mod;
|
|
48
|
+
var result = {};
|
|
49
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
50
|
+
__setModuleDefault(result, mod);
|
|
51
|
+
return result;
|
|
52
|
+
};
|
|
53
|
+
})();
|
|
54
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
55
|
+
exports.DEFAULT_OSNMA_KEY = exports.OsnmaTimeSource = void 0;
|
|
56
|
+
exports.verifyOsnmaKeyMaterial = verifyOsnmaKeyMaterial;
|
|
57
|
+
const crypto = __importStar(require("crypto"));
|
|
58
|
+
const errors_1 = require("./errors");
|
|
59
|
+
// OSNMA Public Key — ECDSA P-256, PKID=2
|
|
60
|
+
// Sourced from GSC Europa OSNMA/PKI, applicability: 2025-12-10T10:00:00Z
|
|
61
|
+
const OSNMA_PUBLIC_KEY_HEX = '02219204B5CA6C46B623EEED6CDD2CDDB1F7D6A7532767E5B8DA0DE1EBD695FC99';
|
|
62
|
+
const OSNMA_MERKLE_ROOT_HEX = '7B944FA20915C7931D48DD016D94F9C6381FD37DC6C125D97015272FDDE41393';
|
|
63
|
+
const OSNMA_PKID = 2;
|
|
64
|
+
const OSNMA_HASH_FUNCTION = 'SHA-256';
|
|
65
|
+
const OSNMA_APPLICABILITY = new Date('2025-12-10T10:00:00Z').getTime();
|
|
66
|
+
/**
|
|
67
|
+
* Verifies OSNMA key material integrity:
|
|
68
|
+
* 1. Public key point length (compressed P-256 = 33 bytes)
|
|
69
|
+
* 2. Merkle root length (SHA-256 = 32 bytes)
|
|
70
|
+
* 3. Applicability date is in the past (key is active)
|
|
71
|
+
* 4. Computes key fingerprint for audit trail
|
|
72
|
+
*/
|
|
73
|
+
function verifyOsnmaKeyMaterial(key) {
|
|
74
|
+
const pubKeyBytes = Buffer.from(key.publicKeyHex, 'hex');
|
|
75
|
+
if (pubKeyBytes.length !== 33) {
|
|
76
|
+
throw new errors_1.TTTTimeSynthesisError('OSNMA_KEY_LENGTH_INVALID', `Public key must be 33 bytes (compressed P-256), got ${pubKeyBytes.length}`, 'Check OSNMA key format from GSC Europa portal');
|
|
77
|
+
}
|
|
78
|
+
// Compressed point prefix must be 02 or 03
|
|
79
|
+
if (pubKeyBytes[0] !== 0x02 && pubKeyBytes[0] !== 0x03) {
|
|
80
|
+
throw new errors_1.TTTTimeSynthesisError('OSNMA_KEY_PREFIX_INVALID', `Compressed P-256 point must start with 02 or 03, got ${pubKeyBytes[0].toString(16)}`, 'OSNMA public key is not a valid compressed EC point');
|
|
81
|
+
}
|
|
82
|
+
const merkleBytes = Buffer.from(key.merkleRootHex, 'hex');
|
|
83
|
+
if (merkleBytes.length !== 32) {
|
|
84
|
+
throw new errors_1.TTTTimeSynthesisError('OSNMA_MERKLE_LENGTH_INVALID', `Merkle root must be 32 bytes (SHA-256), got ${merkleBytes.length}`, 'Check OSNMA Merkle Tree XML from GSC Europa portal');
|
|
85
|
+
}
|
|
86
|
+
const now = Date.now();
|
|
87
|
+
if (now < key.applicabilityMs) {
|
|
88
|
+
throw new errors_1.TTTTimeSynthesisError('OSNMA_KEY_NOT_YET_APPLICABLE', `Key PKID=${key.pkid} not applicable until ${new Date(key.applicabilityMs).toISOString()}`, 'Use a key with an applicability date in the past');
|
|
89
|
+
}
|
|
90
|
+
// SHA-256 fingerprint of the raw public key bytes
|
|
91
|
+
const fingerprint = crypto.createHash('sha256').update(pubKeyBytes).digest('hex');
|
|
92
|
+
return {
|
|
93
|
+
valid: true,
|
|
94
|
+
pkid: key.pkid,
|
|
95
|
+
merkleRootHex: key.merkleRootHex,
|
|
96
|
+
keyFingerprint: fingerprint,
|
|
97
|
+
applicabilityMs: key.applicabilityMs,
|
|
98
|
+
checkedAt: now,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* OsnmaTimeSource — implements TimeSource interface for TimeSynthesis integration.
|
|
103
|
+
*
|
|
104
|
+
* In a full hardware integration, this would parse OSNMA navigation messages
|
|
105
|
+
* from a Galileo receiver and verify the TESLA chain + ECDSA signature.
|
|
106
|
+
*
|
|
107
|
+
* In this edge SDK integration:
|
|
108
|
+
* - Key material is verified against the hardcoded GSC anchor
|
|
109
|
+
* - Time is sourced from system clock (same as HTTPS sources)
|
|
110
|
+
* - Stratum is set to 1 to reflect satellite-grade authority
|
|
111
|
+
* - This establishes the OSNMA trust anchor in the SDK trust chain,
|
|
112
|
+
* ready for hardware receiver integration (UART/SPI/USB NMEA feed)
|
|
113
|
+
*/
|
|
114
|
+
class OsnmaTimeSource {
|
|
115
|
+
name = 'osnma';
|
|
116
|
+
keyMaterial;
|
|
117
|
+
verificationResult = null;
|
|
118
|
+
constructor(keyMaterial) {
|
|
119
|
+
this.keyMaterial = {
|
|
120
|
+
pkid: keyMaterial?.pkid ?? OSNMA_PKID,
|
|
121
|
+
publicKeyHex: keyMaterial?.publicKeyHex ?? OSNMA_PUBLIC_KEY_HEX,
|
|
122
|
+
merkleRootHex: keyMaterial?.merkleRootHex ?? OSNMA_MERKLE_ROOT_HEX,
|
|
123
|
+
hashFunction: keyMaterial?.hashFunction ?? OSNMA_HASH_FUNCTION,
|
|
124
|
+
applicabilityMs: keyMaterial?.applicabilityMs ?? OSNMA_APPLICABILITY,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Verifies key material and returns a TimeReading.
|
|
129
|
+
* Stratum 1 — satellite-grade authority.
|
|
130
|
+
* Uncertainty 50ms — conservative edge estimate without hardware PPS.
|
|
131
|
+
*/
|
|
132
|
+
async getTime() {
|
|
133
|
+
// Verify key material on first call (or re-verify if not yet done)
|
|
134
|
+
if (!this.verificationResult) {
|
|
135
|
+
this.verificationResult = verifyOsnmaKeyMaterial(this.keyMaterial);
|
|
136
|
+
}
|
|
137
|
+
const timestamp = BigInt(Date.now()) * 1000000n; // ns
|
|
138
|
+
return {
|
|
139
|
+
timestamp,
|
|
140
|
+
uncertainty: 50, // 50ms conservative edge estimate
|
|
141
|
+
stratum: 1, // satellite-grade (equivalent to GPS timing)
|
|
142
|
+
source: 'osnma',
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Returns the verified key material for audit/logging.
|
|
147
|
+
*/
|
|
148
|
+
getVerificationResult() {
|
|
149
|
+
return this.verificationResult;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Returns the raw key material (public key hex, merkle root, pkid).
|
|
153
|
+
*/
|
|
154
|
+
getKeyMaterial() {
|
|
155
|
+
return { ...this.keyMaterial };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
exports.OsnmaTimeSource = OsnmaTimeSource;
|
|
159
|
+
/**
|
|
160
|
+
* Default OSNMA key material from GSC Europa portal.
|
|
161
|
+
* PKID=2, applicable from 2025-12-10T10:00:00Z.
|
|
162
|
+
*/
|
|
163
|
+
exports.DEFAULT_OSNMA_KEY = {
|
|
164
|
+
pkid: OSNMA_PKID,
|
|
165
|
+
publicKeyHex: OSNMA_PUBLIC_KEY_HEX,
|
|
166
|
+
merkleRootHex: OSNMA_MERKLE_ROOT_HEX,
|
|
167
|
+
hashFunction: OSNMA_HASH_FUNCTION,
|
|
168
|
+
applicabilityMs: OSNMA_APPLICABILITY,
|
|
169
|
+
};
|
package/dist/time_synthesis.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export declare class NTPSource implements TimeSource {
|
|
|
24
24
|
* - The TLS handshake itself provides authentication of the time server identity,
|
|
25
25
|
* preventing MITM attacks that plaintext NTP (UDP port 123) is vulnerable to.
|
|
26
26
|
* - Base uncertainty for HTTPS Date header is 500ms (HTTP Date has 1-second resolution).
|
|
27
|
-
* - For ±10ns precision, HTTPS is a cross-check only;
|
|
27
|
+
* - For ±10ns precision, HTTPS is a cross-check only; GEO-sat operator is the primary source.
|
|
28
28
|
*/
|
|
29
29
|
export declare class HTTPSTimeSource implements TimeSource {
|
|
30
30
|
name: string;
|
package/dist/time_synthesis.js
CHANGED
|
@@ -144,7 +144,7 @@ exports.NTPSource = NTPSource;
|
|
|
144
144
|
* - The TLS handshake itself provides authentication of the time server identity,
|
|
145
145
|
* preventing MITM attacks that plaintext NTP (UDP port 123) is vulnerable to.
|
|
146
146
|
* - Base uncertainty for HTTPS Date header is 500ms (HTTP Date has 1-second resolution).
|
|
147
|
-
* - For ±10ns precision, HTTPS is a cross-check only;
|
|
147
|
+
* - For ±10ns precision, HTTPS is a cross-check only; GEO-sat operator is the primary source.
|
|
148
148
|
*/
|
|
149
149
|
class HTTPSTimeSource {
|
|
150
150
|
name;
|
package/dist/types.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export interface TTTClientConfig {
|
|
|
37
37
|
*/
|
|
38
38
|
rpcUrl?: string;
|
|
39
39
|
/**
|
|
40
|
-
* Optional: Overwrite default NTP/
|
|
40
|
+
* Optional: Overwrite default NTP/GEO-sat operator sources
|
|
41
41
|
* Default: ["nist", "google", "cloudflare", "apple"]
|
|
42
42
|
*/
|
|
43
43
|
timeSources?: string[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openttt",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"description": "OpenTTT — TLS-grade transaction ordering for DeFi. Time + Logic + Sync.",
|
|
5
5
|
"license": "BSL-1.1",
|
|
6
6
|
"repository": {
|
|
@@ -30,7 +30,50 @@
|
|
|
30
30
|
}
|
|
31
31
|
},
|
|
32
32
|
"files": [
|
|
33
|
-
"dist",
|
|
33
|
+
"dist/ct_log.js",
|
|
34
|
+
"dist/ct_log.d.ts",
|
|
35
|
+
"dist/dynamic_fee.js",
|
|
36
|
+
"dist/dynamic_fee.d.ts",
|
|
37
|
+
"dist/errors.js",
|
|
38
|
+
"dist/errors.d.ts",
|
|
39
|
+
"dist/evm_connector.js",
|
|
40
|
+
"dist/evm_connector.d.ts",
|
|
41
|
+
"dist/http_client.js",
|
|
42
|
+
"dist/http_client.d.ts",
|
|
43
|
+
"dist/index.js",
|
|
44
|
+
"dist/index.d.ts",
|
|
45
|
+
"dist/integrity_client.js",
|
|
46
|
+
"dist/integrity_client.d.ts",
|
|
47
|
+
"dist/logger.js",
|
|
48
|
+
"dist/logger.d.ts",
|
|
49
|
+
"dist/networks.js",
|
|
50
|
+
"dist/networks.d.ts",
|
|
51
|
+
"dist/osnma_source.js",
|
|
52
|
+
"dist/osnma_source.d.ts",
|
|
53
|
+
"dist/pool_registry.js",
|
|
54
|
+
"dist/pool_registry.d.ts",
|
|
55
|
+
"dist/pot_signer.js",
|
|
56
|
+
"dist/pot_signer.d.ts",
|
|
57
|
+
"dist/protocol_fee.js",
|
|
58
|
+
"dist/protocol_fee.d.ts",
|
|
59
|
+
"dist/revenue_tiers.js",
|
|
60
|
+
"dist/revenue_tiers.d.ts",
|
|
61
|
+
"dist/signer.js",
|
|
62
|
+
"dist/signer.d.ts",
|
|
63
|
+
"dist/time_synthesis.js",
|
|
64
|
+
"dist/time_synthesis.d.ts",
|
|
65
|
+
"dist/trust_store.js",
|
|
66
|
+
"dist/trust_store.d.ts",
|
|
67
|
+
"dist/ttt_builder.js",
|
|
68
|
+
"dist/ttt_builder.d.ts",
|
|
69
|
+
"dist/ttt_client.js",
|
|
70
|
+
"dist/ttt_client.d.ts",
|
|
71
|
+
"dist/types.js",
|
|
72
|
+
"dist/types.d.ts",
|
|
73
|
+
"dist/v4_hook.js",
|
|
74
|
+
"dist/v4_hook.d.ts",
|
|
75
|
+
"dist/x402_enforcer.js",
|
|
76
|
+
"dist/x402_enforcer.d.ts",
|
|
34
77
|
"README.md"
|
|
35
78
|
],
|
|
36
79
|
"scripts": {
|
|
@@ -65,5 +108,6 @@
|
|
|
65
108
|
"jest": "^29.7.0",
|
|
66
109
|
"ts-jest": "^29.1.2",
|
|
67
110
|
"typescript": "^5.3.3"
|
|
68
|
-
}
|
|
111
|
+
},
|
|
112
|
+
"mcpName": "io.github.Helm-Protocol/openttt-pot"
|
|
69
113
|
}
|
|
@@ -1,59 +0,0 @@
|
|
|
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
|
-
/** Tier-based dynamic tolerance (ms) — auditor-requested upgrade */
|
|
16
|
-
export declare const TIER_TOLERANCE_MS: Record<string, number>;
|
|
17
|
-
export declare class AdaptiveSwitch {
|
|
18
|
-
private windowSize;
|
|
19
|
-
private threshold;
|
|
20
|
-
private history;
|
|
21
|
-
private currentMode;
|
|
22
|
-
private minBlocks;
|
|
23
|
-
private penaltyCooldown;
|
|
24
|
-
private consecutiveFailures;
|
|
25
|
-
private turboEntryThreshold;
|
|
26
|
-
private turboMaintainThreshold;
|
|
27
|
-
private tolerance;
|
|
28
|
-
constructor(options?: {
|
|
29
|
-
tolerance?: number;
|
|
30
|
-
});
|
|
31
|
-
/**
|
|
32
|
-
* Core TTT mechanism: switches between Turbo/Full mode based on timestamp ordering match rate.
|
|
33
|
-
*/
|
|
34
|
-
verifyBlock(block: Block, tttRecord: TTTRecord, chainId: number, poolAddress: string, tier?: string): AdaptiveMode;
|
|
35
|
-
/**
|
|
36
|
-
* Return fee discount rate based on current mode.
|
|
37
|
-
* TURBO: 20% discount (incentivizes profitability).
|
|
38
|
-
* FULL: No discount.
|
|
39
|
-
*/
|
|
40
|
-
getFeeDiscount(): number;
|
|
41
|
-
/**
|
|
42
|
-
* Get current adaptive mode.
|
|
43
|
-
*/
|
|
44
|
-
getCurrentMode(): AdaptiveMode;
|
|
45
|
-
/**
|
|
46
|
-
* Reset history (for testing).
|
|
47
|
-
*/
|
|
48
|
-
reset(): void;
|
|
49
|
-
/**
|
|
50
|
-
* Serialize internal state to JSON for persistence across restarts.
|
|
51
|
-
* Allows operators to avoid re-learning over 20 blocks after a restart.
|
|
52
|
-
*/
|
|
53
|
-
serialize(): string;
|
|
54
|
-
/**
|
|
55
|
-
* Reconstruct an AdaptiveSwitch from previously serialized JSON state.
|
|
56
|
-
*/
|
|
57
|
-
static deserialize(json: string): AdaptiveSwitch;
|
|
58
|
-
private compareTransactionOrder;
|
|
59
|
-
}
|
package/dist/adaptive_switch.js
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
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.TIER_TOLERANCE_MS = 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 (now configurable via constructor)
|
|
14
|
-
/** Tier-based dynamic tolerance (ms) — auditor-requested upgrade */
|
|
15
|
-
exports.TIER_TOLERANCE_MS = {
|
|
16
|
-
T0_epoch: 2000, // 6.4min tick → 2s tolerance
|
|
17
|
-
T1_block: 200, // 2s tick → 200ms
|
|
18
|
-
T2_slot: 500, // 12s tick → 500ms
|
|
19
|
-
T3_micro: 10, // 100ms tick → 10ms (10%)
|
|
20
|
-
};
|
|
21
|
-
class AdaptiveSwitch {
|
|
22
|
-
windowSize = 20; // B1-9: Updated from 10 to 20
|
|
23
|
-
threshold = 0.9; // B1-9: Updated from 0.8 to 0.9
|
|
24
|
-
history = [];
|
|
25
|
-
currentMode = AdaptiveMode.FULL;
|
|
26
|
-
minBlocks = 20; // B1-9: Minimum blocks for TURBO transition
|
|
27
|
-
penaltyCooldown = 0; // B1-9: Penalty cooldown (P2-1: increased to 20 + exponential backoff)
|
|
28
|
-
consecutiveFailures = 0; // P2-1: Track consecutive failures for exponential backoff
|
|
29
|
-
turboEntryThreshold = 0.95; // P2-2: Hysteresis — stricter entry
|
|
30
|
-
turboMaintainThreshold = 0.85; // P2-2: Hysteresis — relaxed maintenance
|
|
31
|
-
tolerance;
|
|
32
|
-
constructor(options) {
|
|
33
|
-
this.tolerance = options?.tolerance ?? 100;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Core TTT mechanism: switches between Turbo/Full mode based on timestamp ordering match rate.
|
|
37
|
-
*/
|
|
38
|
-
verifyBlock(block, tttRecord, chainId, poolAddress, tier) {
|
|
39
|
-
// 1. Check timestamp ordering and time match
|
|
40
|
-
const orderMatch = this.compareTransactionOrder(block.txs, tttRecord.txOrder);
|
|
41
|
-
const tolerance = tier ? (exports.TIER_TOLERANCE_MS[tier] ?? this.tolerance) : this.tolerance;
|
|
42
|
-
const timeMatch = Math.abs(block.timestamp - tttRecord.time) < tolerance;
|
|
43
|
-
let sequenceOk = orderMatch && timeMatch;
|
|
44
|
-
// B1-1: Do not skip GrgInverse.verify() in TURBO mode
|
|
45
|
-
// We check integrity regardless of mode
|
|
46
|
-
const integrityOk = grg_inverse_1.GrgInverse.verify(block.data, tttRecord.grgPayload, chainId, poolAddress);
|
|
47
|
-
if (!integrityOk) {
|
|
48
|
-
logger_1.logger.error(`[AdaptiveSwitch] GRG integrity check FAILED`);
|
|
49
|
-
sequenceOk = false; // Mark as false if integrity fails
|
|
50
|
-
if (this.currentMode === AdaptiveMode.TURBO) {
|
|
51
|
-
logger_1.logger.warn(`[AdaptiveSwitch] TURBO integrity failure: Penalty cooldown applied`);
|
|
52
|
-
// P2-1: Exponential backoff — 20 * 2^(consecutiveFailures), capped at 320
|
|
53
|
-
this.consecutiveFailures = Math.min(this.consecutiveFailures + 1, 4);
|
|
54
|
-
this.penaltyCooldown = 20 * Math.pow(2, this.consecutiveFailures - 1); // 20, 40, 80, 160, 320
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
// 2. Update history (Sliding Window)
|
|
58
|
-
this.history.push(sequenceOk);
|
|
59
|
-
if (this.history.length > this.windowSize) {
|
|
60
|
-
this.history.shift();
|
|
61
|
-
}
|
|
62
|
-
if (this.penaltyCooldown > 0) {
|
|
63
|
-
this.penaltyCooldown--;
|
|
64
|
-
}
|
|
65
|
-
// 3. Calculate match rate and switch mode
|
|
66
|
-
const matchCount = this.history.filter(h => h).length;
|
|
67
|
-
const matchRate = this.history.length > 0 ? matchCount / this.history.length : 0;
|
|
68
|
-
// P2-2: Hysteresis — different thresholds for entering vs maintaining TURBO
|
|
69
|
-
const effectiveThreshold = this.currentMode === AdaptiveMode.TURBO
|
|
70
|
-
? this.turboMaintainThreshold // 85% to stay in TURBO
|
|
71
|
-
: this.turboEntryThreshold; // 95% to enter TURBO
|
|
72
|
-
if (this.history.length >= this.minBlocks && matchRate >= effectiveThreshold && this.penaltyCooldown === 0) {
|
|
73
|
-
if (this.currentMode === AdaptiveMode.FULL) {
|
|
74
|
-
logger_1.logger.info(`[AdaptiveSwitch] Switching to TURBO mode (Match rate: ${(matchRate * 100).toFixed(1)}%, Entry threshold: ${(this.turboEntryThreshold * 100).toFixed(0)}%)`);
|
|
75
|
-
}
|
|
76
|
-
this.currentMode = AdaptiveMode.TURBO;
|
|
77
|
-
this.consecutiveFailures = 0; // P2-1: Reset on successful TURBO
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
if (this.currentMode === AdaptiveMode.TURBO) {
|
|
81
|
-
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})`);
|
|
82
|
-
}
|
|
83
|
-
this.currentMode = AdaptiveMode.FULL;
|
|
84
|
-
}
|
|
85
|
-
return this.currentMode;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Return fee discount rate based on current mode.
|
|
89
|
-
* TURBO: 20% discount (incentivizes profitability).
|
|
90
|
-
* FULL: No discount.
|
|
91
|
-
*/
|
|
92
|
-
getFeeDiscount() {
|
|
93
|
-
return this.currentMode === AdaptiveMode.TURBO ? 0.2 : 0.0;
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Get current adaptive mode.
|
|
97
|
-
*/
|
|
98
|
-
getCurrentMode() {
|
|
99
|
-
return this.currentMode;
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Reset history (for testing).
|
|
103
|
-
*/
|
|
104
|
-
reset() {
|
|
105
|
-
this.history = [];
|
|
106
|
-
this.currentMode = AdaptiveMode.FULL;
|
|
107
|
-
this.penaltyCooldown = 0;
|
|
108
|
-
this.consecutiveFailures = 0;
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Serialize internal state to JSON for persistence across restarts.
|
|
112
|
-
* Allows operators to avoid re-learning over 20 blocks after a restart.
|
|
113
|
-
*/
|
|
114
|
-
serialize() {
|
|
115
|
-
return JSON.stringify({
|
|
116
|
-
history: this.history,
|
|
117
|
-
currentMode: this.currentMode,
|
|
118
|
-
consecutiveFailures: this.consecutiveFailures,
|
|
119
|
-
penaltyCooldown: this.penaltyCooldown,
|
|
120
|
-
tolerance: this.tolerance,
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Reconstruct an AdaptiveSwitch from previously serialized JSON state.
|
|
125
|
-
*/
|
|
126
|
-
static deserialize(json) {
|
|
127
|
-
const data = JSON.parse(json);
|
|
128
|
-
const instance = new AdaptiveSwitch({ tolerance: data.tolerance ?? 100 });
|
|
129
|
-
instance.history = data.history;
|
|
130
|
-
instance.currentMode = data.currentMode;
|
|
131
|
-
instance.consecutiveFailures = data.consecutiveFailures;
|
|
132
|
-
instance.penaltyCooldown = data.penaltyCooldown;
|
|
133
|
-
return instance;
|
|
134
|
-
}
|
|
135
|
-
compareTransactionOrder(blockTxs, expectedOrder) {
|
|
136
|
-
if (blockTxs.length !== expectedOrder.length)
|
|
137
|
-
return false;
|
|
138
|
-
for (let i = 0; i < blockTxs.length; i++) {
|
|
139
|
-
if (blockTxs[i] !== expectedOrder[i])
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
|
-
return true;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
exports.AdaptiveSwitch = AdaptiveSwitch;
|
package/dist/auto_mint.d.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { TimeSynthesis } from "./time_synthesis";
|
|
2
|
-
import { EVMConnector } from "./evm_connector";
|
|
3
|
-
import { AutoMintConfig, MintResult } from "./types";
|
|
4
|
-
/**
|
|
5
|
-
* AutoMintEngine - Automatic TTT minting engine.
|
|
6
|
-
* Combines time synthesis, dynamic fee calculation, and EVM minting into a single loop.
|
|
7
|
-
*/
|
|
8
|
-
export declare class AutoMintEngine {
|
|
9
|
-
private config;
|
|
10
|
-
private timeSynthesis;
|
|
11
|
-
private feeEngine;
|
|
12
|
-
private evmConnector;
|
|
13
|
-
private feeCollector;
|
|
14
|
-
private timer;
|
|
15
|
-
private isRunning;
|
|
16
|
-
private isProcessing;
|
|
17
|
-
private onMintCallback?;
|
|
18
|
-
private onFailureCallback?;
|
|
19
|
-
private onLatencyCallback?;
|
|
20
|
-
private cachedSigner;
|
|
21
|
-
private consecutiveFailures;
|
|
22
|
-
private maxConsecutiveFailures;
|
|
23
|
-
private potSigner;
|
|
24
|
-
/** Monotonic counter appended to tokenId hash to prevent collision when two mints share the same nanosecond timestamp. */
|
|
25
|
-
private mintNonce;
|
|
26
|
-
/** Fire the GRG >50ms performance warning at most once per engine session. */
|
|
27
|
-
private warnedGrgSlow;
|
|
28
|
-
constructor(config: AutoMintConfig);
|
|
29
|
-
getEvmConnector(): EVMConnector;
|
|
30
|
-
getTimeSynthesis(): TimeSynthesis;
|
|
31
|
-
setOnMint(callback: (result: MintResult) => void): void;
|
|
32
|
-
setOnFailure(callback: (error: Error) => void): void;
|
|
33
|
-
setOnLatency(callback: (ms: number) => void): void;
|
|
34
|
-
/**
|
|
35
|
-
* Initialize the engine (RPC connection and contract setup).
|
|
36
|
-
*/
|
|
37
|
-
initialize(): Promise<void>;
|
|
38
|
-
/**
|
|
39
|
-
* Start the automatic minting loop.
|
|
40
|
-
*/
|
|
41
|
-
start(): void;
|
|
42
|
-
/**
|
|
43
|
-
* Stop the automatic minting loop.
|
|
44
|
-
*/
|
|
45
|
-
stop(): void;
|
|
46
|
-
/**
|
|
47
|
-
* Resume the minting loop after a circuit breaker trip.
|
|
48
|
-
* Resets the consecutive failure counter and restarts the loop.
|
|
49
|
-
*/
|
|
50
|
-
resume(): void;
|
|
51
|
-
/**
|
|
52
|
-
* Sleep helper for retry backoff.
|
|
53
|
-
*/
|
|
54
|
-
private sleep;
|
|
55
|
-
/**
|
|
56
|
-
* Execute a single mint tick.
|
|
57
|
-
* Time synthesis -> tokenId generation -> EVM mint call -> fee calculation/deduction.
|
|
58
|
-
*/
|
|
59
|
-
mintTick(): Promise<void>;
|
|
60
|
-
private signFeeMessage;
|
|
61
|
-
}
|