openttt 0.2.8 → 0.2.10

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/dist/index.d.ts CHANGED
@@ -1,12 +1,10 @@
1
1
  export * from "./evm_connector";
2
2
  export * from "./x402_enforcer";
3
- export * from "./ttt_builder";
4
3
  export * from "./protocol_fee";
5
4
  export * from "./pool_registry";
6
5
  export * from "./v4_hook";
7
6
  export * from "./logger";
8
7
  export * from "./types";
9
- export * from "./ttt_client";
10
8
  export * from "./http_client";
11
9
  export * from "./time_synthesis";
12
10
  export * from "./dynamic_fee";
package/dist/index.js CHANGED
@@ -21,13 +21,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
21
21
  // 위 모듈은 서버 코드에서 직접 경로로 import할 것.
22
22
  __exportStar(require("./evm_connector"), exports);
23
23
  __exportStar(require("./x402_enforcer"), exports);
24
- __exportStar(require("./ttt_builder"), exports);
24
+ // ttt_builder omitted — requires adaptive_switch (server-internal, not in public SDK)
25
25
  __exportStar(require("./protocol_fee"), exports);
26
26
  __exportStar(require("./pool_registry"), exports);
27
27
  __exportStar(require("./v4_hook"), exports);
28
28
  __exportStar(require("./logger"), exports);
29
29
  __exportStar(require("./types"), exports);
30
- __exportStar(require("./ttt_client"), exports);
30
+ // ttt_client omitted — requires auto_mint (server-internal, not in public SDK)
31
31
  __exportStar(require("./http_client"), exports);
32
32
  __exportStar(require("./time_synthesis"), exports);
33
33
  __exportStar(require("./dynamic_fee"), exports);
@@ -14,8 +14,10 @@ export interface IntegrityVerifyResult {
14
14
  export declare class IntegrityClient {
15
15
  private baseUrl;
16
16
  private timeoutMs;
17
+ private apiKey;
17
18
  constructor(baseUrl?: string, options?: {
18
19
  timeoutMs?: number;
20
+ apiKey?: string;
19
21
  });
20
22
  /**
21
23
  * Forward pass: encode data through integrity pipeline (server-side).
@@ -12,9 +12,11 @@ exports.setDefaultIntegrityClient = setDefaultIntegrityClient;
12
12
  class IntegrityClient {
13
13
  baseUrl;
14
14
  timeoutMs;
15
+ apiKey;
15
16
  constructor(baseUrl = "https://integrity.helmprotocol.com/api/v1", options) {
16
17
  this.baseUrl = baseUrl.replace(/\/$/, "");
17
18
  this.timeoutMs = options?.timeoutMs ?? 5000;
19
+ this.apiKey = options?.apiKey ?? (typeof process !== "undefined" ? process.env["INTEGRITY_API_KEY"] : undefined);
18
20
  }
19
21
  /**
20
22
  * Forward pass: encode data through integrity pipeline (server-side).
@@ -27,7 +29,10 @@ class IntegrityClient {
27
29
  try {
28
30
  const resp = await fetch(`${this.baseUrl}/encode`, {
29
31
  method: "POST",
30
- headers: { "Content-Type": "application/json" },
32
+ headers: {
33
+ "Content-Type": "application/json",
34
+ ...(this.apiKey ? { "X-Integrity-Key": this.apiKey } : {}),
35
+ },
31
36
  body: JSON.stringify({
32
37
  data: Buffer.from(data).toString("hex"),
33
38
  chainId: chainId,
@@ -56,7 +61,10 @@ class IntegrityClient {
56
61
  try {
57
62
  const resp = await fetch(`${this.baseUrl}/verify`, {
58
63
  method: "POST",
59
- headers: { "Content-Type": "application/json" },
64
+ headers: {
65
+ "Content-Type": "application/json",
66
+ ...(this.apiKey ? { "X-Integrity-Key": this.apiKey } : {}),
67
+ },
60
68
  body: JSON.stringify({
61
69
  data: Buffer.from(data).toString("hex"),
62
70
  shards: originalShards.map((s) => Buffer.from(s).toString("hex")),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "openttt",
3
- "version": "0.2.8",
4
- "description": "OpenTTT TLS-grade transaction ordering for DeFi. Time + Logic + Sync.",
3
+ "version": "0.2.10",
4
+ "description": "OpenTTT \u2014 TLS-grade transaction ordering for DeFi. Time + Logic + Sync.",
5
5
  "license": "BSL-1.1",
6
6
  "repository": {
7
7
  "type": "git",
@@ -13,7 +13,6 @@
13
13
  "ttt",
14
14
  "proof-of-time",
15
15
  "transaction-ordering",
16
- "grg",
17
16
  "base",
18
17
  "ethereum"
19
18
  ],
@@ -64,10 +63,6 @@
64
63
  "dist/time_synthesis.d.ts",
65
64
  "dist/trust_store.js",
66
65
  "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
66
  "dist/types.js",
72
67
  "dist/types.d.ts",
73
68
  "dist/v4_hook.js",
@@ -1,32 +0,0 @@
1
- import { AdaptiveMode, Block, TTTRecord } from "./adaptive_switch";
2
- import { EVMConnector } from "./evm_connector";
3
- export declare class TTTBuilder {
4
- private mode;
5
- private connector;
6
- private tttBalance;
7
- private adaptiveSwitch;
8
- constructor(connector?: EVMConnector);
9
- /**
10
- * Purchase TTT from the market using EVMConnector.
11
- * P1-5: Router/token addresses configurable. P1-6: 5% slippage protection.
12
- */
13
- purchaseTTT(poolAddress: string, amount: bigint, tokenInAddress?: string, routerAddress?: string, slippageBps?: bigint): Promise<void>;
14
- /**
15
- * Apply TTT to a block by burning it.
16
- * This signals the intention to use TTT for prioritized processing.
17
- */
18
- consumeTick(tokenId: string, tier?: string): Promise<void>;
19
- /**
20
- * Verify block data using the AdaptiveSwitch pipeline.
21
- * Updates the current mode based on verification results.
22
- */
23
- verifyBlock(blockData: Block, tttRecord: TTTRecord, chainId: number, poolAddress: string, tier?: string): Promise<AdaptiveMode>;
24
- /**
25
- * Return the current TURBO/FULL mode.
26
- */
27
- getMode(): AdaptiveMode;
28
- /**
29
- * Helper to get current balance (for testing).
30
- */
31
- getBalance(): bigint;
32
- }
@@ -1,84 +0,0 @@
1
- "use strict";
2
- // sdk/src/ttt_builder.ts — TTT Builder Implementation
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.TTTBuilder = void 0;
5
- const ethers_1 = require("ethers");
6
- const adaptive_switch_1 = require("./adaptive_switch");
7
- const evm_connector_1 = require("./evm_connector");
8
- const dynamic_fee_1 = require("./dynamic_fee");
9
- const logger_1 = require("./logger");
10
- class TTTBuilder {
11
- mode = adaptive_switch_1.AdaptiveMode.FULL;
12
- connector;
13
- tttBalance = 0n;
14
- adaptiveSwitch;
15
- constructor(connector) {
16
- this.connector = connector || new evm_connector_1.EVMConnector();
17
- this.adaptiveSwitch = new adaptive_switch_1.AdaptiveSwitch();
18
- }
19
- /**
20
- * Purchase TTT from the market using EVMConnector.
21
- * P1-5: Router/token addresses configurable. P1-6: 5% slippage protection.
22
- */
23
- async purchaseTTT(poolAddress, amount, tokenInAddress = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", routerAddress = "0x11C9e42994625A0F52906852A9b91e1B69B79B22", slippageBps = 500n // 5% default slippage protection
24
- ) {
25
- logger_1.logger.info(`[TTTBuilder] Purchasing ${amount} TTT from pool: ${poolAddress}`);
26
- // P1-6: Calculate minimum output with slippage protection
27
- const minAmountOut = (amount * (10000n - slippageBps)) / 10000n;
28
- const receipt = await this.connector.swap(routerAddress, tokenInAddress, poolAddress, amount, minAmountOut);
29
- this.tttBalance += amount;
30
- logger_1.logger.info(`[TTTBuilder] Purchase successful. TX: ${receipt.hash}. Current balance: ${this.tttBalance}`);
31
- }
32
- /**
33
- * Apply TTT to a block by burning it.
34
- * This signals the intention to use TTT for prioritized processing.
35
- */
36
- async consumeTick(tokenId, tier = "T1_block") {
37
- logger_1.logger.info(`[TTTBuilder] Consuming TTT tick for token: ${tokenId} (Tier: ${tier})`);
38
- // Look up tier-based costs from TIER_USD_MICRO
39
- // Use BigInt to avoid floating point precision issues (Scale: 1e18)
40
- const usdCostFactor = dynamic_fee_1.TIER_USD_MICRO[tier] || 10000n; // default 0.01 USD
41
- let costTTT = (usdCostFactor * (10n ** 12n)); // Convert to 18 decimals (1e6 * 1e12 = 1e18)
42
- // Apply discount if in TURBO mode (Economic incentive for honest builders)
43
- // R2-P2-3: Use integer-only discount map to avoid float→BigInt precision loss
44
- const DISCOUNT_PERMILLE = { "TURBO": 200n, "FULL": 0n };
45
- const discountPermille = DISCOUNT_PERMILLE[this.adaptiveSwitch.getCurrentMode()] ?? 0n;
46
- if (discountPermille > 0n) {
47
- costTTT = (costTTT * (1000n - discountPermille)) / 1000n;
48
- logger_1.logger.info(`[TTTBuilder] TURBO discount applied: ${Number(discountPermille) / 10}%. Final cost: ${costTTT}`);
49
- }
50
- if (this.tttBalance < costTTT) {
51
- throw new Error(`[TTTBuilder] Insufficient TTT balance to consume tick. Needed: ${costTTT}, Balance: ${this.tttBalance}`);
52
- }
53
- // Call the actual burn function on the TTT contract via the connector.
54
- const grgHash = ethers_1.ethers.keccak256(ethers_1.ethers.toUtf8Bytes(tokenId));
55
- const tierLevel = parseInt(tier.substring(1, 2)) || 1;
56
- await this.connector.burnTTT(costTTT, grgHash, tierLevel);
57
- this.tttBalance -= costTTT;
58
- logger_1.logger.info(`[TTTBuilder] Tick consumed. Cost: ${costTTT}. Remaining balance: ${this.tttBalance}`);
59
- }
60
- /**
61
- * Verify block data using the AdaptiveSwitch pipeline.
62
- * Updates the current mode based on verification results.
63
- */
64
- async verifyBlock(blockData, tttRecord, chainId, poolAddress, tier) {
65
- logger_1.logger.info(`[TTTBuilder] Verifying block at timestamp: ${blockData.timestamp}`);
66
- const result = this.adaptiveSwitch.verifyBlock(blockData, tttRecord, chainId, poolAddress, tier);
67
- this.mode = result;
68
- logger_1.logger.info(`[TTTBuilder] Verification complete. Mode: ${this.mode}`);
69
- return this.mode;
70
- }
71
- /**
72
- * Return the current TURBO/FULL mode.
73
- */
74
- getMode() {
75
- return this.mode;
76
- }
77
- /**
78
- * Helper to get current balance (for testing).
79
- */
80
- getBalance() {
81
- return this.tttBalance;
82
- }
83
- }
84
- exports.TTTBuilder = TTTBuilder;
@@ -1,131 +0,0 @@
1
- import { EventEmitter } from "events";
2
- import { AutoMintConfig, TTTClientConfig, MintResult, HealthStatus } from "./types";
3
- import { HttpOnlyClient, HttpOnlyClientOptions } from "./http_client";
4
- export { HealthStatus } from "./types";
5
- /**
6
- * Typed event map for TTTClient EventEmitter.
7
- */
8
- export interface TTTClientEvents {
9
- mint: [result: MintResult];
10
- error: [error: Error];
11
- alert: [alert: string];
12
- latency: [ms: number];
13
- modeSwitch: [mode: string];
14
- }
15
- /**
16
- * TTTClient - SDK entry point for DEX operators.
17
- * Initializes all internal modules and manages the auto-minting process.
18
- */
19
- export declare class TTTClient extends EventEmitter {
20
- private config;
21
- private autoMintEngine;
22
- private poolRegistry;
23
- private isInitialized;
24
- private mintCount;
25
- private mintFailures;
26
- private totalFeesPaid;
27
- private signer;
28
- private lastTokenId;
29
- private mintLatencies;
30
- private maxLatencyHistory;
31
- private lastMintAt;
32
- private startedAt;
33
- private minBalanceWei;
34
- constructor(config: AutoMintConfig);
35
- /**
36
- * Static factory for Base Mainnet
37
- */
38
- static forBase(config: Omit<TTTClientConfig, 'network'>): Promise<TTTClient>;
39
- /**
40
- * Static factory for Base Sepolia
41
- */
42
- static forSepolia(config: Omit<TTTClientConfig, 'network'>): Promise<TTTClient>;
43
- /**
44
- * Zero-friction sandbox mode — no ETH, no signer, no on-chain interaction.
45
- *
46
- * Returns an HttpOnlyClient that fetches verified time from NIST, Apple,
47
- * Google, and Cloudflare HTTPS endpoints and produces HMAC-signed PoTs.
48
- *
49
- * @example
50
- * // Zero-friction: no wallet, no RPC, no gas
51
- * const client = TTTClient.httpOnly();
52
- * const pot = await client.generatePoT();
53
- * console.log(pot.timestamp, pot.confidence);
54
- *
55
- * // Verify locally (no on-chain check needed)
56
- * const result = client.verifyPoT(pot);
57
- * console.log(result.valid); // true
58
- */
59
- static httpOnly(options?: HttpOnlyClientOptions): HttpOnlyClient;
60
- /**
61
- * Universal factory to create and initialize a client
62
- */
63
- static create(config: TTTClientConfig): Promise<TTTClient>;
64
- /**
65
- * Gracefully shuts down the SDK, stopping all background processes and listeners.
66
- */
67
- destroy(): Promise<void>;
68
- /**
69
- * Initialize the SDK: RPC connection, time sources, fee engine wiring.
70
- */
71
- initialize(): Promise<void>;
72
- /**
73
- * Start the auto-minting process.
74
- */
75
- startAutoMint(): void;
76
- /**
77
- * Stop the auto-minting process.
78
- */
79
- stopAutoMint(): void;
80
- /**
81
- * Resume auto-minting after a circuit breaker trip.
82
- * Resets consecutive failure count and restarts the engine.
83
- */
84
- resume(): void;
85
- /**
86
- * List registered pools.
87
- */
88
- listPools(): string[];
89
- /**
90
- * Get stats for a specific pool.
91
- */
92
- getPoolStats(poolAddress: string): {
93
- minted: bigint;
94
- burned: bigint;
95
- } | null;
96
- /**
97
- * Set minimum ETH balance threshold for health alerts.
98
- */
99
- setMinBalance(weiAmount: bigint): void;
100
- /**
101
- * Register alert callback for real-time notifications.
102
- * Backward compatible: delegates to EventEmitter 'alert' event.
103
- */
104
- onAlert(callback: (alert: string) => void): void;
105
- private emitAlert;
106
- /**
107
- * Record a mint failure (called internally or externally).
108
- */
109
- recordMintFailure(): void;
110
- /**
111
- * Record mint latency in ms (called from auto-mint wrapper).
112
- */
113
- recordMintLatency(ms: number): void;
114
- /**
115
- * Production health check — liveness + readiness + metrics.
116
- * No exceptions: always returns a HealthStatus object.
117
- */
118
- getHealth(): Promise<HealthStatus>;
119
- /**
120
- * Return current SDK status and statistics (balance, mint count, fees, etc.)
121
- */
122
- getStatus(): Promise<{
123
- isInitialized: boolean;
124
- tier: string;
125
- mintCount: number;
126
- totalFeesPaid: string;
127
- balance: string;
128
- tttBalance: string;
129
- lastTokenId: string | null;
130
- }>;
131
- }
@@ -1,441 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TTTClient = void 0;
4
- const ethers_1 = require("ethers");
5
- const events_1 = require("events");
6
- const auto_mint_1 = require("./auto_mint");
7
- const types_1 = require("./types");
8
- const logger_1 = require("./logger");
9
- const pool_registry_1 = require("./pool_registry");
10
- const networks_1 = require("./networks");
11
- const signer_1 = require("./signer");
12
- const http_client_1 = require("./http_client");
13
- /**
14
- * TTTClient - SDK entry point for DEX operators.
15
- * Initializes all internal modules and manages the auto-minting process.
16
- */
17
- class TTTClient extends events_1.EventEmitter {
18
- config;
19
- autoMintEngine;
20
- poolRegistry;
21
- isInitialized = false;
22
- mintCount = 0;
23
- mintFailures = 0;
24
- totalFeesPaid = 0n;
25
- signer = null;
26
- lastTokenId = null;
27
- mintLatencies = [];
28
- maxLatencyHistory;
29
- lastMintAt = null;
30
- startedAt = new Date();
31
- minBalanceWei = ethers_1.ethers.parseEther("0.01"); // 0.01 ETH alert threshold
32
- constructor(config) {
33
- super();
34
- this.config = config;
35
- this.maxLatencyHistory = config.maxLatencyHistory ?? 100;
36
- this.autoMintEngine = new auto_mint_1.AutoMintEngine(config);
37
- this.poolRegistry = new pool_registry_1.PoolRegistry();
38
- // Wire callbacks to update stats + emit events
39
- this.autoMintEngine.setOnMint((result) => {
40
- this.mintCount++;
41
- this.totalFeesPaid += result.protocolFeePaid;
42
- this.lastTokenId = result.tokenId;
43
- this.lastMintAt = new Date();
44
- // Record in registry
45
- this.poolRegistry.recordMint(this.config.poolAddress, 1n);
46
- // Emit typed 'mint' event
47
- this.emit('mint', result);
48
- });
49
- // Wire failure/latency metrics from AutoMint loop to TTTClient
50
- this.autoMintEngine.setOnFailure((error) => {
51
- this.mintFailures++;
52
- this.emit('error', error);
53
- });
54
- this.autoMintEngine.setOnLatency((ms) => {
55
- this.mintLatencies.push(ms);
56
- if (this.mintLatencies.length > this.maxLatencyHistory) {
57
- this.mintLatencies.shift();
58
- }
59
- this.emit('latency', ms);
60
- });
61
- }
62
- /**
63
- * Static factory for Base Mainnet
64
- */
65
- static async forBase(config) {
66
- return this.create({ ...config, network: 'base' });
67
- }
68
- /**
69
- * Static factory for Base Sepolia
70
- */
71
- static async forSepolia(config) {
72
- return this.create({ ...config, network: 'sepolia' });
73
- }
74
- /**
75
- * Zero-friction sandbox mode — no ETH, no signer, no on-chain interaction.
76
- *
77
- * Returns an HttpOnlyClient that fetches verified time from NIST, Apple,
78
- * Google, and Cloudflare HTTPS endpoints and produces HMAC-signed PoTs.
79
- *
80
- * @example
81
- * // Zero-friction: no wallet, no RPC, no gas
82
- * const client = TTTClient.httpOnly();
83
- * const pot = await client.generatePoT();
84
- * console.log(pot.timestamp, pot.confidence);
85
- *
86
- * // Verify locally (no on-chain check needed)
87
- * const result = client.verifyPoT(pot);
88
- * console.log(result.valid); // true
89
- */
90
- static httpOnly(options) {
91
- return new http_client_1.HttpOnlyClient(options);
92
- }
93
- /**
94
- * Universal factory to create and initialize a client
95
- */
96
- static async create(config) {
97
- // 0. Shorthand: privateKey string -> SignerConfig
98
- if (config.privateKey && !config.signer) {
99
- const key = config.privateKey.startsWith('0x') ? config.privateKey : '0x' + config.privateKey;
100
- config = { ...config, signer: { type: 'privateKey', key } };
101
- }
102
- // 0.5. Validation: require either signer or privateKey
103
- if (!config.signer) {
104
- throw new Error('TTTClient requires either `signer` or `privateKey`. Simplest: TTTClient.forBase({ privateKey: process.env.OPERATOR_PK! })');
105
- }
106
- // 0.7. Validate tier — CRITICAL: invalid tier causes setInterval(fn, undefined) = 1ms loop = wallet drain
107
- const tier = config.tier || "T1_block";
108
- if (!types_1.TierIntervals[tier]) {
109
- const validTiers = Object.keys(types_1.TierIntervals).join(', ');
110
- throw new Error(`[TTTClient] Invalid tier "${tier}". Valid tiers: ${validTiers}`);
111
- }
112
- // 0.8. Validate fee rate bounds
113
- if (config.protocolFeeRate !== undefined) {
114
- if (config.protocolFeeRate < 0 || config.protocolFeeRate > 1) {
115
- throw new Error(`[TTTClient] protocolFeeRate must be 0-1 (got ${config.protocolFeeRate}). Example: 0.05 = 5%`);
116
- }
117
- }
118
- // 0.9. Validate network string
119
- if (typeof config.network === 'string' && !networks_1.NETWORKS[config.network]) {
120
- const validNets = Object.keys(networks_1.NETWORKS).join(', ');
121
- throw new Error(`[TTTClient] Unknown network "${config.network}". Valid: ${validNets}. Or pass a custom NetworkConfig object.`);
122
- }
123
- // 1. Resolve network defaults
124
- let net;
125
- if (typeof config.network === 'string') {
126
- net = networks_1.NETWORKS[config.network];
127
- }
128
- else if (config.network) {
129
- net = config.network;
130
- }
131
- else {
132
- net = networks_1.NETWORKS.base;
133
- }
134
- // 2. Create signer via abstraction
135
- const abstractSigner = await (0, signer_1.createSigner)(config.signer);
136
- const signer = abstractSigner.inner;
137
- // 2.5. Validate addresses — prevent accidental mainnet zero-address usage
138
- const contractAddr = config.contractAddress || net.tttAddress;
139
- if (contractAddr === "0x0000000000000000000000000000000000000000") {
140
- throw new Error("[TTTClient] TTT contract address is zero address. On Base Mainnet, you must provide contractAddress in config (contracts not yet deployed).");
141
- }
142
- // 3. Build AutoMintConfig from TTTClientConfig + defaults
143
- const autoMintConfig = {
144
- chainId: net.chainId,
145
- rpcUrl: config.rpcUrl || net.rpcUrl,
146
- signer: signer,
147
- contractAddress: config.contractAddress || net.tttAddress,
148
- feeCollectorAddress: net.protocolFeeAddress,
149
- poolAddress: (() => {
150
- const addr = config.poolAddress;
151
- if (!addr || addr === "0x0000000000000000000000000000000000000000") {
152
- throw new Error("[TTTClient] poolAddress is required. Provide a valid DEX pool address.");
153
- }
154
- return addr;
155
- })(),
156
- tier: config.tier || "T1_block",
157
- timeSources: config.timeSources || ["nist", "google", "cloudflare", "apple"],
158
- protocolFeeRate: config.protocolFeeRate || 0.05,
159
- protocolFeeRecipient: (() => {
160
- const addr = config.protocolFeeRecipient;
161
- if (!addr || addr === "0x0000000000000000000000000000000000000000") {
162
- throw new Error("[TTTClient] protocolFeeRecipient is required. Provide a valid fee recipient address.");
163
- }
164
- return addr;
165
- })(),
166
- fallbackPriceUsd: config.fallbackPriceUsd || 10000n,
167
- maxLatencyHistory: config.maxLatencyHistory,
168
- };
169
- // 4. Instantiate and initialize
170
- const client = new TTTClient(autoMintConfig);
171
- await client.initialize();
172
- if (config.enableGracefulShutdown) {
173
- process.on('SIGINT', async () => {
174
- logger_1.logger.info("[TTTClient] SIGINT received, shutting down gracefully...");
175
- await client.destroy();
176
- process.exit(0);
177
- });
178
- }
179
- return client;
180
- }
181
- /**
182
- * Gracefully shuts down the SDK, stopping all background processes and listeners.
183
- */
184
- async destroy() {
185
- if (!this.isInitialized)
186
- return;
187
- logger_1.logger.info("[TTTClient] Destroying client...");
188
- // 1. Stop auto-mint engine
189
- this.autoMintEngine.stop();
190
- // 2. Unsubscribe all event listeners
191
- this.autoMintEngine.getEvmConnector().unsubscribeAll();
192
- // 3. Clear local state
193
- this.isInitialized = false;
194
- this.signer = null;
195
- logger_1.logger.info("[TTTClient] Client destroyed successfully.");
196
- }
197
- /**
198
- * Initialize the SDK: RPC connection, time sources, fee engine wiring.
199
- */
200
- async initialize() {
201
- if (this.isInitialized)
202
- return;
203
- try {
204
- logger_1.logger.info(`[TTTClient] Initializing for chain ${this.config.chainId}...`);
205
- await this.autoMintEngine.initialize();
206
- const connector = this.autoMintEngine.getEvmConnector();
207
- this.signer = connector.getSigner();
208
- // Register initial pool
209
- await this.poolRegistry.registerPool(this.config.chainId, this.config.poolAddress);
210
- // Validate feeCollectorAddress early before use
211
- if (this.config.feeCollectorAddress && !ethers_1.ethers.isAddress(this.config.feeCollectorAddress)) {
212
- throw new Error(`[TTTClient] Invalid feeCollectorAddress: ${this.config.feeCollectorAddress}`);
213
- }
214
- // Attach ProtocolFee contract if address is provided
215
- if (this.config.feeCollectorAddress) {
216
- const protocolFeeAbi = [
217
- "event FeeCollected(address indexed payer, uint256 amount, uint256 nonce)"
218
- ];
219
- connector.attachProtocolFeeContract(this.config.feeCollectorAddress, protocolFeeAbi);
220
- }
221
- // Subscribe to events
222
- await connector.subscribeToEvents({
223
- onMinted: async (to, tokenId, amount) => {
224
- logger_1.logger.info(`[TTTClient] Event: TTTMinted to ${to}, tokenId: ${tokenId}, amount: ${amount}`);
225
- const myAddr = await this.signer?.getAddress();
226
- if (to.toLowerCase() === myAddr?.toLowerCase()) {
227
- // Logic could go here to update local state
228
- }
229
- },
230
- onBurned: (from, tokenId, amount, tier) => {
231
- logger_1.logger.info(`[TTTClient] Event: TTTBurned from ${from}, tokenId: ${tokenId}, amount: ${amount}, tier: ${tier}`);
232
- this.poolRegistry.recordBurn(this.config.poolAddress, amount);
233
- },
234
- onFeeCollected: (payer, amount, nonce) => {
235
- logger_1.logger.info(`[TTTClient] Event: FeeCollected from ${payer}, amount: ${amount}, nonce: ${nonce}`);
236
- }
237
- });
238
- this.isInitialized = true;
239
- logger_1.logger.info(`[TTTClient] SDK initialized successfully`);
240
- }
241
- catch (error) {
242
- this.isInitialized = false;
243
- this.signer = null;
244
- logger_1.logger.error(`[TTTClient] Initialization failed, state rolled back: ${error}`);
245
- throw error;
246
- }
247
- }
248
- /**
249
- * Start the auto-minting process.
250
- */
251
- startAutoMint() {
252
- if (!this.isInitialized) {
253
- throw new Error("SDK must be initialized before starting auto-mint");
254
- }
255
- this.autoMintEngine.start();
256
- logger_1.logger.info(`[TTTClient] Auto-minting started for tier ${this.config.tier}`);
257
- }
258
- /**
259
- * Stop the auto-minting process.
260
- */
261
- stopAutoMint() {
262
- this.autoMintEngine.stop();
263
- }
264
- /**
265
- * Resume auto-minting after a circuit breaker trip.
266
- * Resets consecutive failure count and restarts the engine.
267
- */
268
- resume() {
269
- this.autoMintEngine.resume();
270
- this.emit('modeSwitch', 'resumed');
271
- logger_1.logger.info(`[TTTClient] Auto-minting resumed`);
272
- }
273
- /**
274
- * List registered pools.
275
- */
276
- listPools() {
277
- return this.poolRegistry.listPools();
278
- }
279
- /**
280
- * Get stats for a specific pool.
281
- */
282
- getPoolStats(poolAddress) {
283
- return this.poolRegistry.getPoolStats(poolAddress);
284
- }
285
- /**
286
- * Set minimum ETH balance threshold for health alerts.
287
- */
288
- setMinBalance(weiAmount) {
289
- this.minBalanceWei = weiAmount;
290
- }
291
- /**
292
- * Register alert callback for real-time notifications.
293
- * Backward compatible: delegates to EventEmitter 'alert' event.
294
- */
295
- onAlert(callback) {
296
- this.on('alert', callback);
297
- }
298
- emitAlert(alert) {
299
- logger_1.logger.warn(`[TTTClient] ALERT: ${alert}`);
300
- this.emit('alert', alert);
301
- }
302
- /**
303
- * Record a mint failure (called internally or externally).
304
- */
305
- recordMintFailure() {
306
- this.mintFailures++;
307
- }
308
- /**
309
- * Record mint latency in ms (called from auto-mint wrapper).
310
- */
311
- recordMintLatency(ms) {
312
- this.mintLatencies.push(ms);
313
- if (this.mintLatencies.length > this.maxLatencyHistory) {
314
- this.mintLatencies.shift();
315
- }
316
- }
317
- /**
318
- * Production health check — liveness + readiness + metrics.
319
- * No exceptions: always returns a HealthStatus object.
320
- */
321
- async getHealth() {
322
- const alerts = [];
323
- let rpcConnected = false;
324
- let balanceSufficient = false;
325
- let ntpSourcesOk = false;
326
- // 1. RPC connectivity check
327
- if (this.isInitialized && this.signer?.provider) {
328
- try {
329
- const blockNumber = await this.signer.provider.getBlockNumber();
330
- rpcConnected = blockNumber > 0;
331
- }
332
- catch {
333
- rpcConnected = false;
334
- alerts.push("RPC connection failed");
335
- }
336
- }
337
- // 2. Balance check
338
- if (this.isInitialized && this.signer?.provider) {
339
- try {
340
- const address = await this.signer.getAddress();
341
- const balance = await this.signer.provider.getBalance(address);
342
- balanceSufficient = balance >= this.minBalanceWei;
343
- if (!balanceSufficient) {
344
- alerts.push(`ETH balance low: ${ethers_1.ethers.formatEther(balance)} ETH (min: ${ethers_1.ethers.formatEther(this.minBalanceWei)})`);
345
- }
346
- }
347
- catch {
348
- alerts.push("Balance check failed");
349
- }
350
- }
351
- // 3. NTP/time source health check via quick synthesis with timeout
352
- try {
353
- const synthResult = await Promise.race([
354
- this.autoMintEngine.getTimeSynthesis().synthesize(),
355
- new Promise((_, reject) => setTimeout(() => reject(new Error("Time synthesis health check timed out")), 3000)),
356
- ]);
357
- if (synthResult && synthResult.sources >= 2 && synthResult.confidence >= 0.5) {
358
- ntpSourcesOk = true;
359
- }
360
- else {
361
- ntpSourcesOk = false;
362
- alerts.push(`Time sources degraded: ${synthResult?.sources ?? 0} source(s), confidence ${synthResult?.confidence?.toFixed(2) ?? "N/A"}`);
363
- }
364
- }
365
- catch {
366
- ntpSourcesOk = false;
367
- alerts.push("Time source health check failed");
368
- }
369
- // 4. Consecutive failure check
370
- const total = this.mintCount + this.mintFailures;
371
- const successRate = total > 0 ? this.mintCount / total : 1;
372
- if (this.mintFailures > 5 && successRate < 0.8) {
373
- alerts.push(`High mint failure rate: ${this.mintFailures} failures, ${(successRate * 100).toFixed(1)}% success`);
374
- }
375
- // 4. Avg latency
376
- const avgLatency = this.mintLatencies.length > 0
377
- ? this.mintLatencies.reduce((a, b) => a + b, 0) / this.mintLatencies.length
378
- : 0;
379
- // 5. Uptime
380
- const uptimeMs = Date.now() - this.startedAt.getTime();
381
- // Emit alerts
382
- for (const alert of alerts) {
383
- this.emitAlert(alert);
384
- }
385
- const healthy = this.isInitialized && rpcConnected && balanceSufficient && alerts.length === 0;
386
- return {
387
- healthy,
388
- checks: {
389
- initialized: this.isInitialized,
390
- rpcConnected,
391
- signerAvailable: this.signer !== null,
392
- balanceSufficient,
393
- ntpSourcesOk,
394
- },
395
- metrics: {
396
- mintCount: this.mintCount,
397
- mintFailures: this.mintFailures,
398
- successRate: Math.round(successRate * 1000) / 1000,
399
- totalFeesPaid: this.totalFeesPaid.toString(),
400
- avgMintLatencyMs: Math.round(avgLatency),
401
- lastMintAt: this.lastMintAt?.toISOString() ?? null,
402
- uptimeMs,
403
- },
404
- alerts,
405
- };
406
- }
407
- /**
408
- * Return current SDK status and statistics (balance, mint count, fees, etc.)
409
- */
410
- async getStatus() {
411
- if (!this.isInitialized || !this.signer) {
412
- throw new Error("SDK must be initialized before getting status");
413
- }
414
- const provider = this.signer.provider;
415
- if (!provider) {
416
- throw new Error("Signer provider is not available");
417
- }
418
- const address = await this.signer.getAddress();
419
- const balance = await provider.getBalance(address);
420
- const formattedBalance = ethers_1.ethers.formatEther(balance);
421
- let tttBalance = 0n;
422
- if (this.lastTokenId) {
423
- try {
424
- tttBalance = await this.autoMintEngine.getEvmConnector().getTTTBalance(address, BigInt(this.lastTokenId));
425
- }
426
- catch (e) {
427
- logger_1.logger.error(`[TTTClient] Failed to fetch TTT balance: ${e}`);
428
- }
429
- }
430
- return {
431
- isInitialized: this.isInitialized,
432
- tier: this.config.tier,
433
- mintCount: this.mintCount,
434
- totalFeesPaid: this.totalFeesPaid.toString(),
435
- balance: formattedBalance,
436
- tttBalance: tttBalance.toString(),
437
- lastTokenId: this.lastTokenId
438
- };
439
- }
440
- }
441
- exports.TTTClient = TTTClient;