openttt 0.1.2 → 0.1.3

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.
Files changed (43) hide show
  1. package/README.md +4 -4
  2. package/dist/adaptive_switch.d.ts +22 -7
  3. package/dist/adaptive_switch.js +52 -15
  4. package/dist/auto_mint.d.ts +22 -7
  5. package/dist/auto_mint.js +107 -30
  6. package/dist/ct_log.d.ts +47 -0
  7. package/dist/ct_log.js +107 -0
  8. package/dist/dynamic_fee.d.ts +13 -2
  9. package/dist/dynamic_fee.js +62 -11
  10. package/dist/errors.d.ts +44 -25
  11. package/dist/errors.js +58 -42
  12. package/dist/evm_connector.d.ts +28 -1
  13. package/dist/evm_connector.js +124 -32
  14. package/dist/index.d.ts +4 -5
  15. package/dist/index.js +4 -5
  16. package/dist/logger.d.ts +36 -4
  17. package/dist/logger.js +70 -11
  18. package/dist/networks.d.ts +21 -0
  19. package/dist/networks.js +30 -4
  20. package/dist/pool_registry.d.ts +9 -0
  21. package/dist/pool_registry.js +37 -0
  22. package/dist/pot_signer.d.ts +15 -0
  23. package/dist/pot_signer.js +28 -0
  24. package/dist/protocol_fee.d.ts +42 -26
  25. package/dist/protocol_fee.js +77 -54
  26. package/dist/revenue_tiers.d.ts +36 -0
  27. package/dist/revenue_tiers.js +83 -0
  28. package/dist/signer.d.ts +1 -2
  29. package/dist/signer.js +72 -14
  30. package/dist/time_synthesis.d.ts +38 -0
  31. package/dist/time_synthesis.js +134 -20
  32. package/dist/trust_store.d.ts +49 -0
  33. package/dist/trust_store.js +89 -0
  34. package/dist/ttt_builder.d.ts +1 -1
  35. package/dist/ttt_builder.js +2 -2
  36. package/dist/ttt_client.d.ts +24 -29
  37. package/dist/ttt_client.js +97 -28
  38. package/dist/types.d.ts +46 -3
  39. package/dist/v4_hook.d.ts +10 -2
  40. package/dist/v4_hook.js +10 -2
  41. package/dist/x402_enforcer.d.ts +17 -2
  42. package/dist/x402_enforcer.js +27 -2
  43. package/package.json +1 -1
@@ -1,32 +1,21 @@
1
- import { AutoMintConfig, TTTClientConfig } from "./types";
1
+ import { EventEmitter } from "events";
2
+ import { AutoMintConfig, TTTClientConfig, MintResult, HealthStatus } from "./types";
3
+ export { HealthStatus } from "./types";
2
4
  /**
3
- * Health status returned by getHealth()
5
+ * Typed event map for TTTClient EventEmitter.
4
6
  */
5
- export interface HealthStatus {
6
- healthy: boolean;
7
- checks: {
8
- initialized: boolean;
9
- rpcConnected: boolean;
10
- signerAvailable: boolean;
11
- balanceSufficient: boolean;
12
- ntpSourcesOk: boolean;
13
- };
14
- metrics: {
15
- mintCount: number;
16
- mintFailures: number;
17
- successRate: number;
18
- totalFeesPaid: string;
19
- avgMintLatencyMs: number;
20
- lastMintAt: string | null;
21
- uptimeMs: number;
22
- };
23
- alerts: string[];
7
+ export interface TTTClientEvents {
8
+ mint: [result: MintResult];
9
+ error: [error: Error];
10
+ alert: [alert: string];
11
+ latency: [ms: number];
12
+ modeSwitch: [mode: string];
24
13
  }
25
14
  /**
26
- * TTTClient - DEX 운영자용 SDK 진입점
27
- * 모든 내부 모듈을 초기화하고 자동 민팅 프로세스를 관리
15
+ * TTTClient - SDK entry point for DEX operators.
16
+ * Initializes all internal modules and manages the auto-minting process.
28
17
  */
29
- export declare class TTTClient {
18
+ export declare class TTTClient extends EventEmitter {
30
19
  private config;
31
20
  private autoMintEngine;
32
21
  private poolRegistry;
@@ -37,10 +26,10 @@ export declare class TTTClient {
37
26
  private signer;
38
27
  private lastTokenId;
39
28
  private mintLatencies;
29
+ private maxLatencyHistory;
40
30
  private lastMintAt;
41
31
  private startedAt;
42
32
  private minBalanceWei;
43
- private onAlertCallback?;
44
33
  constructor(config: AutoMintConfig);
45
34
  /**
46
35
  * Static factory for Base Mainnet
@@ -59,17 +48,22 @@ export declare class TTTClient {
59
48
  */
60
49
  destroy(): Promise<void>;
61
50
  /**
62
- * SDK 초기화: RPC 연결, 시간 소스 설정, 수수료 엔진 연결
51
+ * Initialize the SDK: RPC connection, time sources, fee engine wiring.
63
52
  */
64
53
  initialize(): Promise<void>;
65
54
  /**
66
- * 자동 민팅 프로세스 시작
55
+ * Start the auto-minting process.
67
56
  */
68
57
  startAutoMint(): void;
69
58
  /**
70
- * 자동 민팅 프로세스 정지
59
+ * Stop the auto-minting process.
71
60
  */
72
61
  stopAutoMint(): void;
62
+ /**
63
+ * Resume auto-minting after a circuit breaker trip.
64
+ * Resets consecutive failure count and restarts the engine.
65
+ */
66
+ resume(): void;
73
67
  /**
74
68
  * List registered pools.
75
69
  */
@@ -87,6 +81,7 @@ export declare class TTTClient {
87
81
  setMinBalance(weiAmount: bigint): void;
88
82
  /**
89
83
  * Register alert callback for real-time notifications.
84
+ * Backward compatible: delegates to EventEmitter 'alert' event.
90
85
  */
91
86
  onAlert(callback: (alert: string) => void): void;
92
87
  private emitAlert;
@@ -104,7 +99,7 @@ export declare class TTTClient {
104
99
  */
105
100
  getHealth(): Promise<HealthStatus>;
106
101
  /**
107
- * 현재 SDK 상태 통계 반환 (잔고, 민팅 수, 수수료 )
102
+ * Return current SDK status and statistics (balance, mint count, fees, etc.)
108
103
  */
109
104
  getStatus(): Promise<{
110
105
  isInitialized: boolean;
@@ -2,16 +2,18 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TTTClient = void 0;
4
4
  const ethers_1 = require("ethers");
5
+ const events_1 = require("events");
5
6
  const auto_mint_1 = require("./auto_mint");
7
+ const types_1 = require("./types");
6
8
  const logger_1 = require("./logger");
7
9
  const pool_registry_1 = require("./pool_registry");
8
10
  const networks_1 = require("./networks");
9
11
  const signer_1 = require("./signer");
10
12
  /**
11
- * TTTClient - DEX 운영자용 SDK 진입점
12
- * 모든 내부 모듈을 초기화하고 자동 민팅 프로세스를 관리
13
+ * TTTClient - SDK entry point for DEX operators.
14
+ * Initializes all internal modules and manages the auto-minting process.
13
15
  */
14
- class TTTClient {
16
+ class TTTClient extends events_1.EventEmitter {
15
17
  config;
16
18
  autoMintEngine;
17
19
  poolRegistry;
@@ -22,15 +24,17 @@ class TTTClient {
22
24
  signer = null;
23
25
  lastTokenId = null;
24
26
  mintLatencies = [];
27
+ maxLatencyHistory;
25
28
  lastMintAt = null;
26
29
  startedAt = new Date();
27
30
  minBalanceWei = ethers_1.ethers.parseEther("0.01"); // 0.01 ETH alert threshold
28
- onAlertCallback;
29
31
  constructor(config) {
32
+ super();
30
33
  this.config = config;
34
+ this.maxLatencyHistory = config.maxLatencyHistory ?? 100;
31
35
  this.autoMintEngine = new auto_mint_1.AutoMintEngine(config);
32
36
  this.poolRegistry = new pool_registry_1.PoolRegistry();
33
- // Set up callback to update stats + metrics
37
+ // Wire callbacks to update stats + emit events
34
38
  this.autoMintEngine.setOnMint((result) => {
35
39
  this.mintCount++;
36
40
  this.totalFeesPaid += result.protocolFeePaid;
@@ -38,16 +42,20 @@ class TTTClient {
38
42
  this.lastMintAt = new Date();
39
43
  // Record in registry
40
44
  this.poolRegistry.recordMint(this.config.poolAddress, 1n);
45
+ // Emit typed 'mint' event
46
+ this.emit('mint', result);
41
47
  });
42
- // H2: Wire failure/latency metrics from AutoMint loop to TTTClient
43
- this.autoMintEngine.setOnFailure((_error) => {
48
+ // Wire failure/latency metrics from AutoMint loop to TTTClient
49
+ this.autoMintEngine.setOnFailure((error) => {
44
50
  this.mintFailures++;
51
+ this.emit('error', error);
45
52
  });
46
53
  this.autoMintEngine.setOnLatency((ms) => {
47
54
  this.mintLatencies.push(ms);
48
- if (this.mintLatencies.length > 100) {
55
+ if (this.mintLatencies.length > this.maxLatencyHistory) {
49
56
  this.mintLatencies.shift();
50
57
  }
58
+ this.emit('latency', ms);
51
59
  });
52
60
  }
53
61
  /**
@@ -66,10 +74,36 @@ class TTTClient {
66
74
  * Universal factory to create and initialize a client
67
75
  */
68
76
  static async create(config) {
77
+ // 0. Shorthand: privateKey string -> SignerConfig
78
+ if (config.privateKey && !config.signer) {
79
+ const key = config.privateKey.startsWith('0x') ? config.privateKey : '0x' + config.privateKey;
80
+ config = { ...config, signer: { type: 'privateKey', key } };
81
+ }
82
+ // 0.5. Validation: require either signer or privateKey
83
+ if (!config.signer) {
84
+ throw new Error('TTTClient requires either `signer` or `privateKey`. Simplest: TTTClient.forBase({ privateKey: process.env.OPERATOR_PK! })');
85
+ }
86
+ // 0.7. Validate tier — CRITICAL: invalid tier causes setInterval(fn, undefined) = 1ms loop = wallet drain
87
+ const tier = config.tier || "T1_block";
88
+ if (!types_1.TierIntervals[tier]) {
89
+ const validTiers = Object.keys(types_1.TierIntervals).join(', ');
90
+ throw new Error(`[TTTClient] Invalid tier "${tier}". Valid tiers: ${validTiers}`);
91
+ }
92
+ // 0.8. Validate fee rate bounds
93
+ if (config.protocolFeeRate !== undefined) {
94
+ if (config.protocolFeeRate < 0 || config.protocolFeeRate > 1) {
95
+ throw new Error(`[TTTClient] protocolFeeRate must be 0-1 (got ${config.protocolFeeRate}). Example: 0.05 = 5%`);
96
+ }
97
+ }
98
+ // 0.9. Validate network string
99
+ if (typeof config.network === 'string' && !networks_1.NETWORKS[config.network]) {
100
+ const validNets = Object.keys(networks_1.NETWORKS).join(', ');
101
+ throw new Error(`[TTTClient] Unknown network "${config.network}". Valid: ${validNets}. Or pass a custom NetworkConfig object.`);
102
+ }
69
103
  // 1. Resolve network defaults
70
104
  let net;
71
105
  if (typeof config.network === 'string') {
72
- net = networks_1.NETWORKS[config.network] || networks_1.NETWORKS.base;
106
+ net = networks_1.NETWORKS[config.network];
73
107
  }
74
108
  else if (config.network) {
75
109
  net = config.network;
@@ -92,12 +126,25 @@ class TTTClient {
92
126
  signer: signer,
93
127
  contractAddress: config.contractAddress || net.tttAddress,
94
128
  feeCollectorAddress: net.protocolFeeAddress,
95
- poolAddress: config.poolAddress || "0x0000000000000000000000000000000000000000",
129
+ poolAddress: (() => {
130
+ const addr = config.poolAddress;
131
+ if (!addr || addr === "0x0000000000000000000000000000000000000000") {
132
+ throw new Error("[TTTClient] poolAddress is required. Provide a valid DEX pool address.");
133
+ }
134
+ return addr;
135
+ })(),
96
136
  tier: config.tier || "T1_block",
97
- timeSources: config.timeSources || ["nist", "kriss", "google"],
137
+ timeSources: config.timeSources || ["nist", "google", "cloudflare", "apple"],
98
138
  protocolFeeRate: config.protocolFeeRate || 0.05,
99
- protocolFeeRecipient: config.protocolFeeRecipient || "0x0000000000000000000000000000000000000000",
139
+ protocolFeeRecipient: (() => {
140
+ const addr = config.protocolFeeRecipient;
141
+ if (!addr || addr === "0x0000000000000000000000000000000000000000") {
142
+ throw new Error("[TTTClient] protocolFeeRecipient is required. Provide a valid fee recipient address.");
143
+ }
144
+ return addr;
145
+ })(),
100
146
  fallbackPriceUsd: config.fallbackPriceUsd || 10000n,
147
+ maxLatencyHistory: config.maxLatencyHistory,
101
148
  };
102
149
  // 4. Instantiate and initialize
103
150
  const client = new TTTClient(autoMintConfig);
@@ -128,7 +175,7 @@ class TTTClient {
128
175
  logger_1.logger.info("[TTTClient] Client destroyed successfully.");
129
176
  }
130
177
  /**
131
- * SDK 초기화: RPC 연결, 시간 소스 설정, 수수료 엔진 연결
178
+ * Initialize the SDK: RPC connection, time sources, fee engine wiring.
132
179
  */
133
180
  async initialize() {
134
181
  if (this.isInitialized)
@@ -140,7 +187,7 @@ class TTTClient {
140
187
  this.signer = connector.getSigner();
141
188
  // Register initial pool
142
189
  await this.poolRegistry.registerPool(this.config.chainId, this.config.poolAddress);
143
- // R2-P2-2: Validate feeCollectorAddress early before use
190
+ // Validate feeCollectorAddress early before use
144
191
  if (this.config.feeCollectorAddress && !ethers_1.ethers.isAddress(this.config.feeCollectorAddress)) {
145
192
  throw new Error(`[TTTClient] Invalid feeCollectorAddress: ${this.config.feeCollectorAddress}`);
146
193
  }
@@ -179,7 +226,7 @@ class TTTClient {
179
226
  }
180
227
  }
181
228
  /**
182
- * 자동 민팅 프로세스 시작
229
+ * Start the auto-minting process.
183
230
  */
184
231
  startAutoMint() {
185
232
  if (!this.isInitialized) {
@@ -189,11 +236,20 @@ class TTTClient {
189
236
  logger_1.logger.info(`[TTTClient] Auto-minting started for tier ${this.config.tier}`);
190
237
  }
191
238
  /**
192
- * 자동 민팅 프로세스 정지
239
+ * Stop the auto-minting process.
193
240
  */
194
241
  stopAutoMint() {
195
242
  this.autoMintEngine.stop();
196
243
  }
244
+ /**
245
+ * Resume auto-minting after a circuit breaker trip.
246
+ * Resets consecutive failure count and restarts the engine.
247
+ */
248
+ resume() {
249
+ this.autoMintEngine.resume();
250
+ this.emit('modeSwitch', 'resumed');
251
+ logger_1.logger.info(`[TTTClient] Auto-minting resumed`);
252
+ }
197
253
  /**
198
254
  * List registered pools.
199
255
  */
@@ -214,18 +270,14 @@ class TTTClient {
214
270
  }
215
271
  /**
216
272
  * Register alert callback for real-time notifications.
273
+ * Backward compatible: delegates to EventEmitter 'alert' event.
217
274
  */
218
275
  onAlert(callback) {
219
- this.onAlertCallback = callback;
276
+ this.on('alert', callback);
220
277
  }
221
278
  emitAlert(alert) {
222
279
  logger_1.logger.warn(`[TTTClient] ALERT: ${alert}`);
223
- if (this.onAlertCallback) {
224
- try {
225
- this.onAlertCallback(alert);
226
- }
227
- catch (_) { /* swallow */ }
228
- }
280
+ this.emit('alert', alert);
229
281
  }
230
282
  /**
231
283
  * Record a mint failure (called internally or externally).
@@ -238,8 +290,7 @@ class TTTClient {
238
290
  */
239
291
  recordMintLatency(ms) {
240
292
  this.mintLatencies.push(ms);
241
- // Keep last 100 entries
242
- if (this.mintLatencies.length > 100) {
293
+ if (this.mintLatencies.length > this.maxLatencyHistory) {
243
294
  this.mintLatencies.shift();
244
295
  }
245
296
  }
@@ -251,7 +302,7 @@ class TTTClient {
251
302
  const alerts = [];
252
303
  let rpcConnected = false;
253
304
  let balanceSufficient = false;
254
- let ntpSourcesOk = true; // Assume ok unless we can verify
305
+ let ntpSourcesOk = false;
255
306
  // 1. RPC connectivity check
256
307
  if (this.isInitialized && this.signer?.provider) {
257
308
  try {
@@ -277,7 +328,25 @@ class TTTClient {
277
328
  alerts.push("Balance check failed");
278
329
  }
279
330
  }
280
- // 3. Consecutive failure check
331
+ // 3. NTP/time source health check via quick synthesis with timeout
332
+ try {
333
+ const synthResult = await Promise.race([
334
+ this.autoMintEngine.getTimeSynthesis().synthesize(),
335
+ new Promise((_, reject) => setTimeout(() => reject(new Error("Time synthesis health check timed out")), 3000)),
336
+ ]);
337
+ if (synthResult && synthResult.sources >= 2 && synthResult.confidence >= 0.5) {
338
+ ntpSourcesOk = true;
339
+ }
340
+ else {
341
+ ntpSourcesOk = false;
342
+ alerts.push(`Time sources degraded: ${synthResult?.sources ?? 0} source(s), confidence ${synthResult?.confidence?.toFixed(2) ?? "N/A"}`);
343
+ }
344
+ }
345
+ catch {
346
+ ntpSourcesOk = false;
347
+ alerts.push("Time source health check failed");
348
+ }
349
+ // 4. Consecutive failure check
281
350
  const total = this.mintCount + this.mintFailures;
282
351
  const successRate = total > 0 ? this.mintCount / total : 1;
283
352
  if (this.mintFailures > 5 && successRate < 0.8) {
@@ -316,7 +385,7 @@ class TTTClient {
316
385
  };
317
386
  }
318
387
  /**
319
- * 현재 SDK 상태 통계 반환 (잔고, 민팅 수, 수수료 )
388
+ * Return current SDK status and statistics (balance, mint count, fees, etc.)
320
389
  */
321
390
  async getStatus() {
322
391
  if (!this.isInitialized || !this.signer) {
package/dist/types.d.ts CHANGED
@@ -9,9 +9,19 @@ export declare const TierIntervals: Record<TierType, number>;
9
9
  */
10
10
  export interface TTTClientConfig {
11
11
  /**
12
- * Required: Signer configuration (PrivateKey, Turnkey, Privy, KMS)
12
+ * Signer configuration (PrivateKey, Turnkey, Privy, KMS).
13
+ * Required unless `privateKey` shorthand is provided.
13
14
  */
14
- signer: SignerConfig;
15
+ signer?: SignerConfig;
16
+ /**
17
+ * Shorthand: pass a raw private key string directly.
18
+ * If provided (and `signer` is not), auto-converts to { type: 'privateKey', key: ... }.
19
+ * Accepts with or without '0x' prefix.
20
+ *
21
+ * @example
22
+ * TTTClient.forBase({ privateKey: process.env.OPERATOR_PK! })
23
+ */
24
+ privateKey?: string;
15
25
  /**
16
26
  * Optional: Network selection (preset "base", "sepolia" or custom NetworkConfig)
17
27
  * Default: "base" (Base Mainnet)
@@ -28,7 +38,7 @@ export interface TTTClientConfig {
28
38
  rpcUrl?: string;
29
39
  /**
30
40
  * Optional: Overwrite default NTP/KTSat sources
31
- * Default: ["nist", "kriss", "google"]
41
+ * Default: ["nist", "google", "cloudflare", "apple"]
32
42
  */
33
43
  timeSources?: string[];
34
44
  /**
@@ -57,6 +67,12 @@ export interface TTTClientConfig {
57
67
  * Optional: Automatically register SIGINT handler for graceful shutdown
58
68
  */
59
69
  enableGracefulShutdown?: boolean;
70
+ /**
71
+ * Optional: Maximum number of mint latency samples to keep in the ring buffer.
72
+ * Used for avgMintLatencyMs calculation in health checks.
73
+ * Default: 100
74
+ */
75
+ maxLatencyHistory?: number;
60
76
  }
61
77
  /**
62
78
  * Internal configuration used by engines.
@@ -75,6 +91,8 @@ export interface AutoMintConfig {
75
91
  protocolFeeRate: number;
76
92
  protocolFeeRecipient: string;
77
93
  fallbackPriceUsd?: bigint;
94
+ maxLatencyHistory?: number;
95
+ potSignerKeyPath?: string;
78
96
  }
79
97
  export interface MintResult {
80
98
  tokenId: string;
@@ -138,9 +156,34 @@ export interface ProofOfTime {
138
156
  source: string;
139
157
  timestamp: bigint;
140
158
  uncertainty: number;
159
+ stratum?: number;
141
160
  }[];
142
161
  nonce: string;
143
162
  expiresAt: bigint;
144
163
  issuerSignature?: PotSignature;
145
164
  }
165
+ /**
166
+ * Health status returned by TTTClient.getHealth().
167
+ * Provides liveness, readiness, and operational metrics.
168
+ */
169
+ export interface HealthStatus {
170
+ healthy: boolean;
171
+ checks: {
172
+ initialized: boolean;
173
+ rpcConnected: boolean;
174
+ signerAvailable: boolean;
175
+ balanceSufficient: boolean;
176
+ ntpSourcesOk: boolean;
177
+ };
178
+ metrics: {
179
+ mintCount: number;
180
+ mintFailures: number;
181
+ successRate: number;
182
+ totalFeesPaid: string;
183
+ avgMintLatencyMs: number;
184
+ lastMintAt: string | null;
185
+ uptimeMs: number;
186
+ };
187
+ alerts: string[];
188
+ }
146
189
  export type { PotSignature } from "./pot_signer";
package/dist/v4_hook.d.ts CHANGED
@@ -3,8 +3,16 @@ import { ProtocolFeeCollector } from "./protocol_fee";
3
3
  import { FeeCalculation } from "./dynamic_fee";
4
4
  import { BeforeSwapParams, AfterSwapParams } from "./types";
5
5
  /**
6
- * UniswapV4Hook - TTT-based Uniswap V4 Hook Simulation
7
- * Provides actual logic for TTT balance verification and fee management.
6
+ * UniswapV4Hook - TTT-based Uniswap V4 Hook Simulation (SDK-side)
7
+ *
8
+ * This is a simulation/SDK-side hook that mirrors the logic of a Uniswap V4 hook
9
+ * for off-chain validation and testing. It is NOT the actual Solidity on-chain hook.
10
+ *
11
+ * The actual V4 hook contract should implement IHooks from @uniswap/v4-core
12
+ * (see: https://github.com/Uniswap/v4-core/blob/main/src/interfaces/IHooks.sol).
13
+ *
14
+ * Provides TTT balance verification and fee management logic that can be used
15
+ * to validate swap eligibility before submitting on-chain transactions.
8
16
  */
9
17
  export declare class UniswapV4Hook {
10
18
  private evmConnector;
package/dist/v4_hook.js CHANGED
@@ -4,8 +4,16 @@ exports.UniswapV4Hook = void 0;
4
4
  const ethers_1 = require("ethers");
5
5
  const logger_1 = require("./logger");
6
6
  /**
7
- * UniswapV4Hook - TTT-based Uniswap V4 Hook Simulation
8
- * Provides actual logic for TTT balance verification and fee management.
7
+ * UniswapV4Hook - TTT-based Uniswap V4 Hook Simulation (SDK-side)
8
+ *
9
+ * This is a simulation/SDK-side hook that mirrors the logic of a Uniswap V4 hook
10
+ * for off-chain validation and testing. It is NOT the actual Solidity on-chain hook.
11
+ *
12
+ * The actual V4 hook contract should implement IHooks from @uniswap/v4-core
13
+ * (see: https://github.com/Uniswap/v4-core/blob/main/src/interfaces/IHooks.sol).
14
+ *
15
+ * Provides TTT balance verification and fee management logic that can be used
16
+ * to validate swap eligibility before submitting on-chain transactions.
9
17
  */
10
18
  class UniswapV4Hook {
11
19
  evmConnector;
@@ -11,9 +11,24 @@ export interface SwapDetails {
11
11
  export declare class X402Enforcer {
12
12
  private static getCost;
13
13
  /**
14
- * Deducts TTT ticks from local balance and determines Adaptive Mode.
14
+ * Deducts TTT ticks from the provided balance and determines Adaptive Mode.
15
+ *
16
+ * **Important:** By default, the `balance` parameter is an SDK-local value
17
+ * (tracked in-memory by the caller). It is NOT verified against the on-chain
18
+ * TTT token balance. This is sufficient for hot-path tick accounting where
19
+ * on-chain settlement happens separately via `deductOnChain()`.
20
+ *
21
+ * @param feeEngine - Dynamic fee engine for cost calculation
22
+ * @param swap - Swap details (user, tokens, amount)
23
+ * @param balance - SDK-local TTT balance (not on-chain unless verifyOnChain=true)
24
+ * @param tier - Stratum tier (0-3)
25
+ * @param mode - Current adaptive mode (Turbo/Full)
26
+ * @param verifyOnChain - If true, checks on-chain TTT balance via EVMConnector
27
+ * before deducting. Requires `connector` and `tokenId`. Default: false.
28
+ * @param connector - EVMConnector instance (required when verifyOnChain=true)
29
+ * @param tokenId - Token ID for on-chain balance lookup (required when verifyOnChain=true)
15
30
  */
16
- static deductTick(feeEngine: DynamicFeeEngine, swap: SwapDetails, balance: bigint, tier: number, mode: AdaptiveMode): Promise<{
31
+ static deductTick(feeEngine: DynamicFeeEngine, swap: SwapDetails, balance: bigint, tier: number, mode: AdaptiveMode, verifyOnChain?: boolean, connector?: EVMConnector, tokenId?: bigint): Promise<{
17
32
  success: boolean;
18
33
  remaining: bigint;
19
34
  mode: AdaptiveMode;
@@ -17,10 +17,35 @@ class X402Enforcer {
17
17
  return feeCalc.tttAmount;
18
18
  }
19
19
  /**
20
- * Deducts TTT ticks from local balance and determines Adaptive Mode.
20
+ * Deducts TTT ticks from the provided balance and determines Adaptive Mode.
21
+ *
22
+ * **Important:** By default, the `balance` parameter is an SDK-local value
23
+ * (tracked in-memory by the caller). It is NOT verified against the on-chain
24
+ * TTT token balance. This is sufficient for hot-path tick accounting where
25
+ * on-chain settlement happens separately via `deductOnChain()`.
26
+ *
27
+ * @param feeEngine - Dynamic fee engine for cost calculation
28
+ * @param swap - Swap details (user, tokens, amount)
29
+ * @param balance - SDK-local TTT balance (not on-chain unless verifyOnChain=true)
30
+ * @param tier - Stratum tier (0-3)
31
+ * @param mode - Current adaptive mode (Turbo/Full)
32
+ * @param verifyOnChain - If true, checks on-chain TTT balance via EVMConnector
33
+ * before deducting. Requires `connector` and `tokenId`. Default: false.
34
+ * @param connector - EVMConnector instance (required when verifyOnChain=true)
35
+ * @param tokenId - Token ID for on-chain balance lookup (required when verifyOnChain=true)
21
36
  */
22
- static async deductTick(feeEngine, swap, balance, tier, mode) {
37
+ static async deductTick(feeEngine, swap, balance, tier, mode, verifyOnChain = false, connector, tokenId) {
23
38
  const cost = await this.getCost(feeEngine, tier);
39
+ // Optional on-chain balance verification before deducting
40
+ if (verifyOnChain) {
41
+ if (!connector || tokenId === undefined) {
42
+ throw new Error("[x402] verifyOnChain requires both connector and tokenId parameters");
43
+ }
44
+ const onChainBalance = await connector.getTTTBalance(swap.user, tokenId);
45
+ if (onChainBalance < cost) {
46
+ throw new Error(`[x402] On-chain balance insufficient for user ${swap.user}. Required: ${cost}, On-chain: ${onChainBalance}.`);
47
+ }
48
+ }
24
49
  if (balance < cost) {
25
50
  throw new Error(`[x402] Insufficient TTT ticks for user ${swap.user}. Required: ${cost}, Have: ${balance}.`);
26
51
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openttt",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "OpenTTT — TLS-grade transaction ordering for DeFi. Time + Logic + Sync.",
5
5
  "license": "BSL-1.1",
6
6
  "repository": {