openttt 0.2.11 → 0.2.12

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.
@@ -1,122 +0,0 @@
1
- "use strict";
2
- /**
3
- * Integrity Client — replaces local integrity computation with server-side API call.
4
- * Core pipeline source code stays in Helm private repo. Only API calls go through npm SDK.
5
- *
6
- * Drop-in replacement interface for local encode() and verify() operations.
7
- */
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.IntegrityClient = void 0;
10
- exports.getDefaultIntegrityClient = getDefaultIntegrityClient;
11
- exports.setDefaultIntegrityClient = setDefaultIntegrityClient;
12
- class IntegrityClient {
13
- baseUrl;
14
- timeoutMs;
15
- apiKey;
16
- constructor(baseUrl = "https://integrity.helmprotocol.com/api/v1", options) {
17
- this.baseUrl = baseUrl.replace(/\/$/, "");
18
- this.timeoutMs = options?.timeoutMs ?? 5000;
19
- this.apiKey = options?.apiKey ?? (typeof process !== "undefined" ? process.env["INTEGRITY_API_KEY"] : undefined);
20
- }
21
- /**
22
- * Forward pass: encode data through integrity pipeline (server-side).
23
- *
24
- * @returns Array of Uint8Array shards
25
- */
26
- async encode(data, chainId, poolAddress) {
27
- const controller = new AbortController();
28
- const timer = setTimeout(() => controller.abort(), this.timeoutMs);
29
- try {
30
- const resp = await fetch(`${this.baseUrl}/encode`, {
31
- method: "POST",
32
- headers: {
33
- "Content-Type": "application/json",
34
- ...(this.apiKey ? { "X-Integrity-Key": this.apiKey } : {}),
35
- },
36
- body: JSON.stringify({
37
- data: Buffer.from(data).toString("hex"),
38
- chainId: chainId,
39
- poolAddress,
40
- }),
41
- signal: controller.signal,
42
- });
43
- if (!resp.ok) {
44
- throw new Error(`Integrity API error: ${resp.status} ${resp.statusText}`);
45
- }
46
- const result = await resp.json();
47
- return result.shards.map((hex) => Buffer.from(hex, "hex"));
48
- }
49
- finally {
50
- clearTimeout(timer);
51
- }
52
- }
53
- /**
54
- * Verify: check data integrity (server-side).
55
- *
56
- * @returns boolean — true if data matches the original shards
57
- */
58
- async verify(data, originalShards, chainId, poolAddress) {
59
- const controller = new AbortController();
60
- const timer = setTimeout(() => controller.abort(), this.timeoutMs);
61
- try {
62
- const resp = await fetch(`${this.baseUrl}/verify`, {
63
- method: "POST",
64
- headers: {
65
- "Content-Type": "application/json",
66
- ...(this.apiKey ? { "X-Integrity-Key": this.apiKey } : {}),
67
- },
68
- body: JSON.stringify({
69
- data: Buffer.from(data).toString("hex"),
70
- shards: originalShards.map((s) => Buffer.from(s).toString("hex")),
71
- chainId: chainId,
72
- poolAddress,
73
- }),
74
- signal: controller.signal,
75
- });
76
- if (!resp.ok) {
77
- throw new Error(`Integrity API error: ${resp.status} ${resp.statusText}`);
78
- }
79
- const result = await resp.json();
80
- return result.valid;
81
- }
82
- finally {
83
- clearTimeout(timer);
84
- }
85
- }
86
- /**
87
- * Health check — ping the integrity API server.
88
- * Returns true if reachable within timeoutMs.
89
- */
90
- async isReachable() {
91
- const controller = new AbortController();
92
- const timer = setTimeout(() => controller.abort(), this.timeoutMs);
93
- try {
94
- const resp = await fetch(`${this.baseUrl}/health`, {
95
- method: "GET",
96
- signal: controller.signal,
97
- });
98
- return resp.ok;
99
- }
100
- catch {
101
- return false;
102
- }
103
- finally {
104
- clearTimeout(timer);
105
- }
106
- }
107
- }
108
- exports.IntegrityClient = IntegrityClient;
109
- /**
110
- * Singleton default client — uses production integrity API endpoint.
111
- * Can be overridden via setDefaultIntegrityClient() for testing/staging.
112
- */
113
- let _defaultClient = null;
114
- function getDefaultIntegrityClient() {
115
- if (!_defaultClient) {
116
- _defaultClient = new IntegrityClient();
117
- }
118
- return _defaultClient;
119
- }
120
- function setDefaultIntegrityClient(client) {
121
- _defaultClient = client;
122
- }
@@ -1,82 +0,0 @@
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;
@@ -1,169 +0,0 @@
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
- };
@@ -1,72 +0,0 @@
1
- import { FeeCalculation } from "./dynamic_fee";
2
- import { EVMConnector } from "./evm_connector";
3
- /**
4
- * Pluggable replay cache interface for signature deduplication.
5
- * Implement this to use Redis, database, or other external stores.
6
- */
7
- export interface ReplayCache {
8
- has(key: string): Promise<boolean>;
9
- set(key: string, ttlMs: number): Promise<void>;
10
- }
11
- /**
12
- * Default in-memory replay cache with bounded size and TTL eviction.
13
- * Suitable for single-process deployments; use a distributed ReplayCache
14
- * implementation (e.g., Redis) for multi-node setups.
15
- */
16
- export declare class InMemoryReplayCache implements ReplayCache {
17
- private entries;
18
- private readonly maxEntries;
19
- private readonly defaultTtlMs;
20
- private lastPruneTime;
21
- private static readonly PRUNE_INTERVAL_MS;
22
- constructor(maxEntries?: number, defaultTtlMs?: number);
23
- has(key: string): Promise<boolean>;
24
- set(key: string, ttlMs: number): Promise<void>;
25
- private pruneIfNeeded;
26
- }
27
- /**
28
- * ProtocolFeeCollector - Handles Helm protocol fee collection and verification.
29
- * Includes EIP-712 signature verification for x402 compliance.
30
- */
31
- export declare class ProtocolFeeCollector {
32
- private totalCollected;
33
- private chainId;
34
- private verifyingContract;
35
- private replayCache;
36
- private evmConnector;
37
- private protocolFeeRecipient;
38
- private feeContract;
39
- constructor(chainId: number, verifyingContract: string, evmConnector: EVMConnector, protocolFeeRecipient: string, replayCache?: ReplayCache);
40
- /**
41
- * R3-P0-2: Verify chainId matches the actual connected network.
42
- * Must be called after EVMConnector.connect() to prevent cross-chain signature replay.
43
- */
44
- validateChainId(): Promise<void>;
45
- private getFeeContract;
46
- /**
47
- * Collect minting fee (Stablecoin).
48
- * @param feeCalc - Fee calculation result from DynamicFeeEngine.
49
- * @param signature - EIP-712 signature (required, for x402 verification).
50
- * @param user - Signer address.
51
- * @param nonce - Anti-replay nonce.
52
- * @param deadline - Signature expiration timestamp.
53
- */
54
- collectMintFee(feeCalc: FeeCalculation, signature: string, user: string, nonce: bigint, deadline: number): Promise<void>;
55
- /**
56
- * Collect burn fee.
57
- * @param feeCalc - Fee calculation result from DynamicFeeEngine.
58
- * @param signature - EIP-712 signature (required).
59
- * @param user - Signer address.
60
- * @param nonce - Anti-replay nonce.
61
- * @param deadline - Signature expiration timestamp.
62
- */
63
- collectBurnFee(feeCalc: FeeCalculation, signature: string, user: string, nonce: bigint, deadline: number): Promise<void>;
64
- /**
65
- * Return total fees collected so far.
66
- */
67
- getCollectedFees(): Promise<bigint>;
68
- /**
69
- * EIP-712 signature verification (x402 compliance).
70
- */
71
- private verifySignature;
72
- }
@@ -1,199 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ProtocolFeeCollector = exports.InMemoryReplayCache = void 0;
4
- const ethers_1 = require("ethers");
5
- const logger_1 = require("./logger");
6
- /**
7
- * Default in-memory replay cache with bounded size and TTL eviction.
8
- * Suitable for single-process deployments; use a distributed ReplayCache
9
- * implementation (e.g., Redis) for multi-node setups.
10
- */
11
- class InMemoryReplayCache {
12
- entries = new Map();
13
- maxEntries;
14
- defaultTtlMs;
15
- lastPruneTime = 0;
16
- static PRUNE_INTERVAL_MS = 60000;
17
- constructor(maxEntries = 10000, defaultTtlMs = 3600000) {
18
- this.maxEntries = maxEntries;
19
- this.defaultTtlMs = defaultTtlMs;
20
- }
21
- async has(key) {
22
- this.pruneIfNeeded();
23
- const ts = this.entries.get(key);
24
- if (ts === undefined)
25
- return false;
26
- if (Date.now() - ts > this.defaultTtlMs) {
27
- this.entries.delete(key);
28
- return false;
29
- }
30
- return true;
31
- }
32
- async set(key, ttlMs) {
33
- this.pruneIfNeeded();
34
- this.entries.set(key, Date.now());
35
- }
36
- pruneIfNeeded() {
37
- const now = Date.now();
38
- if (now - this.lastPruneTime < InMemoryReplayCache.PRUNE_INTERVAL_MS &&
39
- this.entries.size <= this.maxEntries) {
40
- return;
41
- }
42
- this.lastPruneTime = now;
43
- for (const [sig, ts] of this.entries) {
44
- if (now - ts > this.defaultTtlMs) {
45
- this.entries.delete(sig);
46
- }
47
- }
48
- // If still over limit, remove oldest entries
49
- if (this.entries.size > this.maxEntries) {
50
- const sorted = [...this.entries.entries()].sort((a, b) => a[1] - b[1]);
51
- const toRemove = sorted.slice(0, sorted.length - this.maxEntries);
52
- for (const [sig] of toRemove) {
53
- this.entries.delete(sig);
54
- }
55
- }
56
- }
57
- }
58
- exports.InMemoryReplayCache = InMemoryReplayCache;
59
- /**
60
- * ProtocolFeeCollector - Handles Helm protocol fee collection and verification.
61
- * Includes EIP-712 signature verification for x402 compliance.
62
- */
63
- class ProtocolFeeCollector {
64
- totalCollected = 0n;
65
- chainId;
66
- verifyingContract;
67
- replayCache;
68
- evmConnector;
69
- protocolFeeRecipient;
70
- feeContract = null;
71
- constructor(chainId, verifyingContract, evmConnector, protocolFeeRecipient, replayCache) {
72
- // R3-P0-2: Validate chainId is a positive integer to prevent cross-chain replay
73
- if (!Number.isInteger(chainId) || chainId <= 0) {
74
- throw new Error(`[ProtocolFee] Invalid chainId: ${chainId}. Must be a positive integer.`);
75
- }
76
- this.chainId = chainId;
77
- this.verifyingContract = ethers_1.ethers.getAddress(verifyingContract);
78
- this.evmConnector = evmConnector;
79
- this.protocolFeeRecipient = ethers_1.ethers.getAddress(protocolFeeRecipient);
80
- this.replayCache = replayCache ?? new InMemoryReplayCache();
81
- }
82
- /**
83
- * R3-P0-2: Verify chainId matches the actual connected network.
84
- * Must be called after EVMConnector.connect() to prevent cross-chain signature replay.
85
- */
86
- async validateChainId() {
87
- const provider = this.evmConnector.getProvider();
88
- const network = await provider.getNetwork();
89
- if (Number(network.chainId) !== this.chainId) {
90
- throw new Error(`[ProtocolFee] Chain ID mismatch: configured ${this.chainId}, network reports ${network.chainId}. Cross-chain replay risk!`);
91
- }
92
- }
93
- getFeeContract() {
94
- if (this.feeContract)
95
- return this.feeContract;
96
- const abi = [
97
- "function collectFee(address token, uint256 amount, bytes calldata signature, uint256 nonce, uint256 deadline) external"
98
- ];
99
- // ProtocolFeeCollector uses verifyingContract as the ProtocolFee.sol address
100
- this.feeContract = new ethers_1.ethers.Contract(this.verifyingContract, abi, this.evmConnector.getSigner());
101
- return this.feeContract;
102
- }
103
- /**
104
- * Collect minting fee (Stablecoin).
105
- * @param feeCalc - Fee calculation result from DynamicFeeEngine.
106
- * @param signature - EIP-712 signature (required, for x402 verification).
107
- * @param user - Signer address.
108
- * @param nonce - Anti-replay nonce.
109
- * @param deadline - Signature expiration timestamp.
110
- */
111
- async collectMintFee(feeCalc, signature, user, nonce, deadline) {
112
- try {
113
- await this.verifySignature(feeCalc, signature, user, nonce, deadline);
114
- // Actual on-chain collection
115
- const contract = this.getFeeContract();
116
- const tx = await contract.collectFee(ethers_1.ethers.getAddress(feeCalc.feeTokenAddress), feeCalc.protocolFeeUsd, signature, nonce, deadline);
117
- await tx.wait();
118
- this.totalCollected += feeCalc.protocolFeeUsd;
119
- logger_1.logger.info(`[ProtocolFee] Mint fee collected on-chain: ${feeCalc.protocolFeeUsd} ${feeCalc.feeToken}. TX: ${tx.hash}`);
120
- }
121
- catch (error) {
122
- throw new Error(`[ProtocolFee] Mint fee collection failed: ${(error instanceof Error ? error.message : String(error))}`);
123
- }
124
- }
125
- /**
126
- * Collect burn fee.
127
- * @param feeCalc - Fee calculation result from DynamicFeeEngine.
128
- * @param signature - EIP-712 signature (required).
129
- * @param user - Signer address.
130
- * @param nonce - Anti-replay nonce.
131
- * @param deadline - Signature expiration timestamp.
132
- */
133
- async collectBurnFee(feeCalc, signature, user, nonce, deadline) {
134
- try {
135
- await this.verifySignature(feeCalc, signature, user, nonce, deadline);
136
- // Actual on-chain collection
137
- const contract = this.getFeeContract();
138
- const tx = await contract.collectFee(ethers_1.ethers.getAddress(feeCalc.feeTokenAddress), feeCalc.protocolFeeUsd, signature, nonce, deadline);
139
- await tx.wait();
140
- this.totalCollected += feeCalc.protocolFeeUsd;
141
- logger_1.logger.info(`[ProtocolFee] Burn fee collected on-chain: ${feeCalc.protocolFeeUsd} ${feeCalc.feeToken}. TX: ${tx.hash}`);
142
- }
143
- catch (error) {
144
- throw new Error(`[ProtocolFee] Burn fee collection failed: ${(error instanceof Error ? error.message : String(error))}`);
145
- }
146
- }
147
- /**
148
- * Return total fees collected so far.
149
- */
150
- async getCollectedFees() {
151
- return this.totalCollected;
152
- }
153
- /**
154
- * EIP-712 signature verification (x402 compliance).
155
- */
156
- async verifySignature(feeCalc, signature, user, nonce, deadline) {
157
- // B1-2 + P1-2: Replay protection via pluggable cache
158
- if (await this.replayCache.has(signature)) {
159
- throw new Error("Signature already used (replay protection)");
160
- }
161
- // B1-2: Deadline check
162
- const now = Math.floor(Date.now() / 1000);
163
- if (deadline < now) {
164
- throw new Error("Signature deadline expired");
165
- }
166
- const normalizedUser = ethers_1.ethers.getAddress(user);
167
- const domain = {
168
- name: "OpenTTT_ProtocolFee",
169
- version: "1",
170
- chainId: this.chainId,
171
- verifyingContract: this.verifyingContract
172
- };
173
- const types = {
174
- CollectFee: [
175
- { name: "token", type: "address" },
176
- { name: "amount", type: "uint256" },
177
- { name: "nonce", type: "uint256" },
178
- { name: "deadline", type: "uint256" }
179
- ]
180
- };
181
- const value = {
182
- token: ethers_1.ethers.getAddress(feeCalc.feeTokenAddress),
183
- amount: feeCalc.protocolFeeUsd,
184
- nonce: nonce,
185
- deadline: deadline
186
- };
187
- try {
188
- const recoveredAddress = ethers_1.ethers.verifyTypedData(domain, types, value, signature);
189
- if (ethers_1.ethers.getAddress(recoveredAddress) !== normalizedUser) {
190
- throw new Error("Invalid EIP-712 signature: signer mismatch");
191
- }
192
- await this.replayCache.set(signature, 3600000); // Mark as used with 1h TTL
193
- }
194
- catch (error) {
195
- throw new Error(`[ProtocolFee] Signature verification failed: ${(error instanceof Error ? error.message : String(error))}`);
196
- }
197
- }
198
- }
199
- exports.ProtocolFeeCollector = ProtocolFeeCollector;
@@ -1,36 +0,0 @@
1
- /**
2
- * Revenue Tier Configuration
3
- * Reflects the TTT Labs pricing strategy: Free/Sponsor-backed T0 up to Institutional T3.
4
- */
5
- export declare enum RevenueTier {
6
- T0_EPOCH = "T0_EPOCH",
7
- T1_BLOCK = "T1_BLOCK",
8
- T2_SLOT = "T2_SLOT",
9
- T3_MICRO = "T3_MICRO"
10
- }
11
- export interface TierConfig {
12
- tier: RevenueTier;
13
- name: string;
14
- interval: string;
15
- pricePerTick: number;
16
- currency: string;
17
- model: string;
18
- target: string;
19
- sponsorEligible: boolean;
20
- }
21
- export interface SponsorConfig {
22
- sponsor: string;
23
- tier: RevenueTier;
24
- monthlyBudgetUsd: number;
25
- startDate: string;
26
- endDate: string;
27
- }
28
- export declare const REVENUE_TIERS: Record<RevenueTier, TierConfig>;
29
- /**
30
- * Calculate projected monthly cost based on tier and throughput.
31
- */
32
- export declare function calculateMonthlyCost(tier: RevenueTier, ticksPerDay: number): number;
33
- /**
34
- * Determine the appropriate tier based on a usage description.
35
- */
36
- export declare function getTierForUseCase(useCase: string): RevenueTier;