openttt 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +52 -30
  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/grg_api_client.d.ts +41 -0
  15. package/dist/grg_api_client.js +116 -0
  16. package/dist/http_client.d.ts +98 -0
  17. package/dist/http_client.js +252 -0
  18. package/dist/index.d.ts +5 -5
  19. package/dist/index.js +5 -5
  20. package/dist/logger.d.ts +36 -4
  21. package/dist/logger.js +70 -11
  22. package/dist/networks.d.ts +21 -0
  23. package/dist/networks.js +30 -4
  24. package/dist/pool_registry.d.ts +9 -0
  25. package/dist/pool_registry.js +37 -0
  26. package/dist/pot_signer.d.ts +15 -0
  27. package/dist/pot_signer.js +28 -0
  28. package/dist/protocol_fee.d.ts +42 -26
  29. package/dist/protocol_fee.js +77 -54
  30. package/dist/revenue_tiers.d.ts +36 -0
  31. package/dist/revenue_tiers.js +83 -0
  32. package/dist/signer.d.ts +1 -2
  33. package/dist/signer.js +72 -14
  34. package/dist/time_synthesis.d.ts +38 -0
  35. package/dist/time_synthesis.js +131 -21
  36. package/dist/trust_store.d.ts +49 -0
  37. package/dist/trust_store.js +89 -0
  38. package/dist/ttt_builder.d.ts +1 -1
  39. package/dist/ttt_builder.js +2 -2
  40. package/dist/ttt_client.d.ts +42 -29
  41. package/dist/ttt_client.js +117 -28
  42. package/dist/types.d.ts +46 -3
  43. package/dist/v4_hook.d.ts +10 -2
  44. package/dist/v4_hook.js +10 -2
  45. package/dist/x402_enforcer.d.ts +17 -2
  46. package/dist/x402_enforcer.js +27 -2
  47. package/package.json +6 -2
  48. package/dist/golay.d.ts +0 -6
  49. package/dist/golay.js +0 -166
  50. package/dist/grg_forward.d.ts +0 -11
  51. package/dist/grg_forward.js +0 -74
  52. package/dist/grg_inverse.d.ts +0 -7
  53. package/dist/grg_inverse.js +0 -100
  54. package/dist/grg_pipeline.d.ts +0 -13
  55. package/dist/grg_pipeline.js +0 -64
  56. package/dist/reed_solomon.d.ts +0 -12
  57. package/dist/reed_solomon.js +0 -179
  58. package/vendor/helm-crypto/golay.d.ts +0 -6
  59. package/vendor/helm-crypto/golay.js +0 -167
  60. package/vendor/helm-crypto/golay.js.map +0 -1
  61. package/vendor/helm-crypto/grg_forward.d.ts +0 -22
  62. package/vendor/helm-crypto/grg_forward.js +0 -89
  63. package/vendor/helm-crypto/grg_forward.js.map +0 -1
  64. package/vendor/helm-crypto/grg_inverse.d.ts +0 -16
  65. package/vendor/helm-crypto/grg_inverse.js +0 -118
  66. package/vendor/helm-crypto/grg_inverse.js.map +0 -1
  67. package/vendor/helm-crypto/grg_pipeline.d.ts +0 -13
  68. package/vendor/helm-crypto/grg_pipeline.js +0 -66
  69. package/vendor/helm-crypto/grg_pipeline.js.map +0 -1
  70. package/vendor/helm-crypto/index.d.ts +0 -5
  71. package/vendor/helm-crypto/index.js +0 -17
  72. package/vendor/helm-crypto/index.js.map +0 -1
  73. package/vendor/helm-crypto/logger.d.ts +0 -6
  74. package/vendor/helm-crypto/logger.js +0 -11
  75. package/vendor/helm-crypto/logger.js.map +0 -1
  76. package/vendor/helm-crypto/reed_solomon.d.ts +0 -37
  77. package/vendor/helm-crypto/reed_solomon.js +0 -210
  78. package/vendor/helm-crypto/reed_solomon.js.map +0 -1
package/dist/auto_mint.js CHANGED
@@ -2,18 +2,22 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AutoMintEngine = void 0;
4
4
  const ethers_1 = require("ethers");
5
- const crypto_1 = require("crypto");
6
5
  const time_synthesis_1 = require("./time_synthesis");
7
6
  const dynamic_fee_1 = require("./dynamic_fee");
8
7
  const evm_connector_1 = require("./evm_connector");
9
8
  const protocol_fee_1 = require("./protocol_fee");
10
9
  const pot_signer_1 = require("./pot_signer");
10
+ const helm_crypto_1 = require("../vendor/helm-crypto");
11
11
  const types_1 = require("./types");
12
12
  const logger_1 = require("./logger");
13
13
  const errors_1 = require("./errors");
14
+ /** Maximum retry attempts for RPC-dependent operations within a single tick */
15
+ const MINT_TICK_MAX_RETRIES = 3;
16
+ /** Backoff durations in ms for each retry attempt (1s, 2s, 4s) */
17
+ const MINT_TICK_BACKOFF_MS = [1000, 2000, 4000];
14
18
  /**
15
- * AutoMintEngine - TTT 자동 민팅 엔진
16
- * 시간 합성, 동적 수수료 계산, EVM 민팅을 하나의 루프로 결합
19
+ * AutoMintEngine - Automatic TTT minting engine.
20
+ * Combines time synthesis, dynamic fee calculation, and EVM minting into a single loop.
17
21
  */
18
22
  class AutoMintEngine {
19
23
  config;
@@ -31,6 +35,10 @@ class AutoMintEngine {
31
35
  consecutiveFailures = 0;
32
36
  maxConsecutiveFailures = 5;
33
37
  potSigner = null;
38
+ /** Monotonic counter appended to tokenId hash to prevent collision when two mints share the same nanosecond timestamp. */
39
+ mintNonce = BigInt(Date.now());
40
+ /** Fire the GRG >50ms performance warning at most once per engine session. */
41
+ warnedGrgSlow = false;
34
42
  constructor(config) {
35
43
  this.config = config;
36
44
  this.timeSynthesis = new time_synthesis_1.TimeSynthesis({ sources: config.timeSources });
@@ -43,11 +51,16 @@ class AutoMintEngine {
43
51
  this.cachedSigner = config.signer;
44
52
  }
45
53
  // Initialize Ed25519 PoT signer for non-repudiation
46
- this.potSigner = new pot_signer_1.PotSigner();
54
+ this.potSigner = config.potSignerKeyPath
55
+ ? pot_signer_1.PotSigner.createOrLoad(config.potSignerKeyPath)
56
+ : new pot_signer_1.PotSigner();
47
57
  }
48
58
  getEvmConnector() {
49
59
  return this.evmConnector;
50
60
  }
61
+ getTimeSynthesis() {
62
+ return this.timeSynthesis;
63
+ }
51
64
  setOnMint(callback) {
52
65
  this.onMintCallback = callback;
53
66
  }
@@ -58,13 +71,13 @@ class AutoMintEngine {
58
71
  this.onLatencyCallback = callback;
59
72
  }
60
73
  /**
61
- * 엔진 초기화 (RPC 연결 컨트랙트 설정)
74
+ * Initialize the engine (RPC connection and contract setup).
62
75
  */
63
76
  async initialize() {
64
77
  try {
65
78
  const signerOrKey = this.config.signer || this.config.privateKey;
66
79
  if (!signerOrKey)
67
- throw new errors_1.TTTConfigError("[AutoMint] Signer or Private Key is required", "Missing both 'signer' and 'privateKey' in config", "Provide a valid ethers.Signer or a private key string in your configuration.");
80
+ throw new errors_1.TTTConfigError(errors_1.ERROR_CODES.CONFIG_MISSING_SIGNER, "[AutoMint] Signer or Private Key is required", "Missing both 'signer' and 'privateKey' in config", "Provide a valid ethers.Signer or a private key string in your configuration.");
68
81
  await this.evmConnector.connect(this.config.rpcUrl, signerOrKey);
69
82
  await this.feeEngine.connect(this.config.rpcUrl);
70
83
  this.cachedSigner = this.evmConnector.getSigner();
@@ -73,7 +86,9 @@ class AutoMintEngine {
73
86
  "function burn(uint256 amount, bytes32 grgHash, uint256 tier) external",
74
87
  "function balanceOf(address account, uint256 id) external view returns (uint256)",
75
88
  "event TTTMinted(address indexed to, uint256 indexed tokenId, uint256 amount)",
76
- "event TTTBurned(address indexed from, uint256 indexed tokenId, uint256 amount, uint256 tier)"
89
+ "event TTTBurned(address indexed from, uint256 indexed tokenId, uint256 amount, uint256 tier)",
90
+ // CT Log equivalent: every PoT is publicly auditable on-chain
91
+ evm_connector_1.EVMConnector.POT_ANCHORED_EVENT_ABI
77
92
  ];
78
93
  this.evmConnector.attachContract(this.config.contractAddress, tttAbi);
79
94
  if (this.config.feeCollectorAddress) {
@@ -91,7 +106,7 @@ class AutoMintEngine {
91
106
  }
92
107
  }
93
108
  /**
94
- * 자동 민팅 루프 시작
109
+ * Start the automatic minting loop.
95
110
  */
96
111
  start() {
97
112
  if (this.isRunning)
@@ -135,7 +150,7 @@ class AutoMintEngine {
135
150
  logger_1.logger.info(`[AutoMint] Loop started for tier ${this.config.tier} (${interval}ms)`);
136
151
  }
137
152
  /**
138
- * 자동 민팅 루프 정지
153
+ * Stop the automatic minting loop.
139
154
  */
140
155
  stop() {
141
156
  if (this.timer) {
@@ -146,11 +161,26 @@ class AutoMintEngine {
146
161
  logger_1.logger.info(`[AutoMint] Loop stopped`);
147
162
  }
148
163
  /**
149
- * 단일 민트 실행
150
- * 시간합성 tokenId 생성 EVM mint 호출 → 수수료 계산/차감
164
+ * Resume the minting loop after a circuit breaker trip.
165
+ * Resets the consecutive failure counter and restarts the loop.
166
+ */
167
+ resume() {
168
+ this.consecutiveFailures = 0;
169
+ logger_1.logger.info(`[AutoMint] Consecutive failures reset, resuming...`);
170
+ this.start();
171
+ }
172
+ /**
173
+ * Sleep helper for retry backoff.
174
+ */
175
+ sleep(ms) {
176
+ return new Promise(resolve => setTimeout(resolve, ms));
177
+ }
178
+ /**
179
+ * Execute a single mint tick.
180
+ * Time synthesis -> tokenId generation -> EVM mint call -> fee calculation/deduction.
151
181
  */
152
182
  async mintTick() {
153
- // 1. 시간 합성 (Time Synthesis)
183
+ // 1. Time Synthesis
154
184
  const synthesized = await this.timeSynthesis.synthesize();
155
185
  if (!synthesized) {
156
186
  logger_1.logger.warn(`[AutoMint] Time synthesis returned null/undefined, skipping tick`);
@@ -158,35 +188,78 @@ class AutoMintEngine {
158
188
  }
159
189
  // Fix-12: Integrity check
160
190
  if (synthesized.confidence === 0 || synthesized.stratum >= 16) {
161
- throw new errors_1.TTTTimeSynthesisError(`[AutoMint] Synthesis integrity check failed`, `confidence=${synthesized.confidence}, stratum=${synthesized.stratum}`, `Check NTP sources or network connectivity.`);
191
+ throw new errors_1.TTTTimeSynthesisError(errors_1.ERROR_CODES.TIME_SYNTHESIS_INTEGRITY_FAILED, `[AutoMint] Synthesis integrity check failed`, `confidence=${synthesized.confidence}, stratum=${synthesized.stratum}`, `Check NTP sources or network connectivity.`);
162
192
  }
163
193
  // 1-1. PoT Generation & Validation (W1-1)
164
194
  const pot = await this.timeSynthesis.generateProofOfTime();
165
195
  if (pot.confidence < 0.5) {
166
- throw new errors_1.TTTTimeSynthesisError(`[PoT] Insufficient confidence`, `Calculated confidence ${pot.confidence} is below required 0.5`, `Ensure more NTP sources are reachable or decrease uncertainty.`);
196
+ throw new errors_1.TTTTimeSynthesisError(errors_1.ERROR_CODES.TIME_SYNTHESIS_INSUFFICIENT_CONFIDENCE, `[PoT] Insufficient confidence`, `Calculated confidence ${pot.confidence} is below required 0.5`, `Ensure more NTP sources are reachable or decrease uncertainty.`);
167
197
  }
168
- const potHash = ethers_1.ethers.keccak256(ethers_1.ethers.toUtf8Bytes(JSON.stringify(pot, (key, value) => typeof value === 'bigint' ? value.toString() : value)));
198
+ // Deterministic potHash via ABI.encode field order is fixed,
199
+ // independent of JS engine key ordering. External verifiers can
200
+ // reproduce this hash from the same PoT fields.
201
+ const nonceHash = ethers_1.ethers.keccak256(ethers_1.ethers.toUtf8Bytes(pot.nonce));
202
+ const potHash = ethers_1.ethers.keccak256(ethers_1.ethers.AbiCoder.defaultAbiCoder().encode(["uint64", "uint64", "uint8", "uint8", "uint32", "bytes32"], [
203
+ pot.timestamp,
204
+ pot.expiresAt,
205
+ pot.sources,
206
+ pot.stratum,
207
+ Math.round(pot.confidence * 1_000_000),
208
+ nonceHash
209
+ ]));
169
210
  // 1-2. Ed25519 issuer signature for non-repudiation
170
211
  if (this.potSigner) {
171
212
  pot.issuerSignature = this.potSigner.signPot(potHash);
172
213
  logger_1.logger.info(`[AutoMint] PoT signed by issuer ${this.potSigner.getPubKeyHex().substring(0, 16)}...`);
173
214
  }
174
- // 2. tokenId 생성 (keccak256)
175
- // chainId, poolAddress, timestamp 기반 유니크 ID
176
- const tokenId = ethers_1.ethers.keccak256(ethers_1.ethers.AbiCoder.defaultAbiCoder().encode(["uint256", "address", "uint64"], [BigInt(this.config.chainId), this.config.poolAddress, synthesized.timestamp]));
177
- // 3. 수수료 계산
215
+ // 2. Generate tokenId (keccak256)
216
+ // Unique ID based on chainId, poolAddress, timestamp, and a monotonic nonce
217
+ // to prevent collision if two mints occur at the same nanosecond timestamp.
218
+ const nonceSuffix = this.mintNonce;
219
+ this.mintNonce++;
220
+ const tokenId = ethers_1.ethers.keccak256(ethers_1.ethers.AbiCoder.defaultAbiCoder().encode(["uint256", "address", "uint64", "uint256"], [BigInt(this.config.chainId), this.config.poolAddress, synthesized.timestamp, nonceSuffix]));
221
+ // 3. Fee calculation
178
222
  const feeCalculation = await this.feeEngine.calculateMintFee(this.config.tier);
179
- // 4. EVM mint 호출
180
- // grgHash는 현재 tokenId를 기반으로 생성 (실제 구현에선 복잡한 GRG 페이로드 사용 가능)
181
- const grgHash = tokenId;
182
- // 수취인 주소 (기본적으로 signer 주소)
223
+ // 4. EVM mint call — run GRG integrity pipeline
224
+ const grgPayload = ethers_1.ethers.AbiCoder.defaultAbiCoder().encode(["bytes32", "bytes32", "uint64", "uint8"], [tokenId, potHash, synthesized.timestamp, pot.sources]);
225
+ const grgStart = Date.now();
226
+ const grgShards = helm_crypto_1.GrgForward.encode(ethers_1.ethers.getBytes(grgPayload), this.config.chainId, this.config.poolAddress);
227
+ const grgElapsed = Date.now() - grgStart;
228
+ logger_1.logger.info(`[AutoMint] GRG pipeline completed in ${grgElapsed}ms`);
229
+ if (grgElapsed > 50 && !this.warnedGrgSlow) {
230
+ this.warnedGrgSlow = true;
231
+ logger_1.logger.warn(`[AutoMint] GRG pipeline took ${grgElapsed}ms (>50ms threshold). Consider offloading to a Worker Thread for T3_micro tiers.`);
232
+ }
233
+ // On-chain hash = keccak256 of concatenated GRG-encoded shards
234
+ const grgHash = ethers_1.ethers.keccak256(ethers_1.ethers.concat(grgShards));
235
+ // Recipient address (defaults to signer address)
183
236
  if (!this.cachedSigner) {
184
- throw new errors_1.TTTSignerError("[AutoMint] Signer not initialized", "cachedSigner is null", "Initialize the engine before calling mintTick().");
237
+ throw new errors_1.TTTSignerError(errors_1.ERROR_CODES.SIGNER_NOT_INITIALIZED, "[AutoMint] Signer not initialized", "cachedSigner is null", "Initialize the engine before calling mintTick().");
185
238
  }
186
239
  const recipient = await this.cachedSigner.getAddress();
187
240
  logger_1.logger.info(`[AutoMint] Executing mint: tokenId=${tokenId.substring(0, 10)}... amount=${feeCalculation.tttAmount}`);
188
- const receipt = await this.evmConnector.mintTTT(recipient, feeCalculation.tttAmount, grgHash, potHash);
189
- // 5. 수수료 차감/기록 (실제 컨트랙트에서 처리되거나 SDK 레벨에서 추적)
241
+ // Retry loop for RPC-dependent mint operation (max 3 attempts, backoff 1s/2s/4s)
242
+ let receipt;
243
+ let lastError = null;
244
+ for (let attempt = 0; attempt < MINT_TICK_MAX_RETRIES; attempt++) {
245
+ try {
246
+ receipt = await this.evmConnector.mintTTT(recipient, feeCalculation.tttAmount, grgHash, potHash);
247
+ lastError = null;
248
+ break;
249
+ }
250
+ catch (err) {
251
+ lastError = err instanceof Error ? err : new Error(String(err));
252
+ if (attempt < MINT_TICK_MAX_RETRIES - 1) {
253
+ const backoff = MINT_TICK_BACKOFF_MS[attempt];
254
+ logger_1.logger.warn(`[AutoMint] Mint attempt ${attempt + 1}/${MINT_TICK_MAX_RETRIES} failed, retrying in ${backoff}ms: ${lastError.message}`);
255
+ await this.sleep(backoff);
256
+ }
257
+ }
258
+ }
259
+ if (lastError || !receipt) {
260
+ throw lastError || new Error("[AutoMint] Mint failed after all retries");
261
+ }
262
+ // 5. Fee deduction/recording (handled by contract or tracked at SDK level)
190
263
  // W2-3: Actual ProtocolFeeCollector call
191
264
  let actualFeePaid = feeCalculation.protocolFeeUsd;
192
265
  if (this.feeCollector && this.config.feeCollectorAddress) {
@@ -194,7 +267,9 @@ class AutoMintEngine {
194
267
  // NOTE: Single-threaded JS guarantees atomicity between nonce generation,
195
268
  // signing, and collection below. If running multiple AutoMintEngine instances
196
269
  // (e.g., worker_threads or cluster), a separate nonce manager with locking is required.
197
- const nonce = BigInt("0x" + (0, crypto_1.randomBytes)(8).toString("hex")); // Cryptographic nonce
270
+ // Sequential nonce: query contract for current nonce, matching ProtocolFee.sol's require(nonces[msg.sender] == nonce)
271
+ const feeContract = new ethers_1.ethers.Contract(this.config.feeCollectorAddress, ["function getNonce(address) external view returns (uint256)"], this.evmConnector.getProvider());
272
+ const nonce = BigInt(await feeContract.getNonce(recipient));
198
273
  const deadline = Math.floor(Date.now() / 1000) + 3600; // 1 hour validity
199
274
  const signature = await this.signFeeMessage(feeCalculation, nonce, deadline);
200
275
  const user = recipient;
@@ -206,6 +281,8 @@ class AutoMintEngine {
206
281
  actualFeePaid = 0n;
207
282
  }
208
283
  }
284
+ // CT Log equivalent: log PoT anchor info for subgraph indexers
285
+ logger_1.logger.info(`[AutoMint] PoTAnchored: timestamp=${synthesized.timestamp}, grgHash=${grgHash}, stratum=${synthesized.stratum}, potHash=${potHash}`);
209
286
  logger_1.logger.info(`[AutoMint] Mint success: tx=${receipt.hash}, feePaid=${actualFeePaid} (USDC eq)`);
210
287
  if (this.onMintCallback) {
211
288
  this.onMintCallback({
@@ -220,15 +297,15 @@ class AutoMintEngine {
220
297
  }
221
298
  async signFeeMessage(feeCalc, nonce, deadline) {
222
299
  if (!this.cachedSigner) {
223
- throw new errors_1.TTTSignerError("[AutoMint] Signer not initialized", "cachedSigner is null", "Ensure initialize() was called successfully.");
300
+ throw new errors_1.TTTSignerError(errors_1.ERROR_CODES.SIGNER_NOT_INITIALIZED, "[AutoMint] Signer not initialized", "cachedSigner is null", "Ensure initialize() was called successfully.");
224
301
  }
225
302
  // Type casting to handle signTypedData if available on the signer (Wallet supports it)
226
303
  const signer = this.cachedSigner;
227
304
  if (typeof signer.signTypedData !== 'function') {
228
- throw new errors_1.TTTSignerError("[AutoMint] Provided signer does not support signTypedData (EIP-712)", `Signer type ${signer.constructor.name} missing signTypedData`, "Use a Wallet or a signer that implements EIP-712 signTypedData.");
305
+ throw new errors_1.TTTSignerError(errors_1.ERROR_CODES.SIGNER_NO_EIP712, "[AutoMint] Provided signer does not support signTypedData (EIP-712)", `Signer type ${signer.constructor.name} missing signTypedData`, "Use a Wallet or a signer that implements EIP-712 signTypedData.");
229
306
  }
230
307
  const domain = {
231
- name: "Helm Protocol",
308
+ name: "OpenTTT_ProtocolFee",
232
309
  version: "1",
233
310
  chainId: this.config.chainId,
234
311
  verifyingContract: this.config.feeCollectorAddress
@@ -0,0 +1,47 @@
1
+ /**
2
+ * PoT Certificate Transparency Log Client
3
+ * Tracks all PoT anchoring events and provides query/audit capabilities.
4
+ */
5
+ export interface PoTAnchorEntry {
6
+ id: string;
7
+ stratum: string;
8
+ grgHash: string;
9
+ potHash: string;
10
+ timestamp: string;
11
+ blockNumber: string;
12
+ txHash: string;
13
+ builderAddress: string;
14
+ }
15
+ export declare class PoTCTLog {
16
+ private subgraphUrl;
17
+ constructor(subgraphUrl: string);
18
+ /**
19
+ * Query PoT anchors with filters.
20
+ */
21
+ queryAnchors(filter: {
22
+ startTime?: number;
23
+ endTime?: number;
24
+ stratum?: string;
25
+ limit?: number;
26
+ }): Promise<PoTAnchorEntry[]>;
27
+ /**
28
+ * Get audit trail for a specific transaction.
29
+ */
30
+ getAuditTrail(txHash: string): Promise<PoTAnchorEntry | null>;
31
+ /**
32
+ * Calculate builder performance score.
33
+ */
34
+ getBuilderScore(builderAddress: string): Promise<{
35
+ totalAnchors: number;
36
+ turboRate: number;
37
+ avgLatencyMs: number;
38
+ }>;
39
+ /**
40
+ * Get global network statistics.
41
+ */
42
+ getNetworkStats(): Promise<{
43
+ totalAnchors: number;
44
+ uniqueBuilders: number;
45
+ avgTurboRate: number;
46
+ }>;
47
+ }
package/dist/ct_log.js ADDED
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ /**
3
+ * PoT Certificate Transparency Log Client
4
+ * Tracks all PoT anchoring events and provides query/audit capabilities.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.PoTCTLog = void 0;
8
+ class PoTCTLog {
9
+ subgraphUrl;
10
+ constructor(subgraphUrl) {
11
+ this.subgraphUrl = subgraphUrl;
12
+ }
13
+ /**
14
+ * Query PoT anchors with filters.
15
+ */
16
+ async queryAnchors(filter) {
17
+ const { startTime, endTime, stratum, limit = 100 } = filter;
18
+ const whereClause = [];
19
+ if (startTime)
20
+ whereClause.push(`timestamp_gte: "${startTime}"`);
21
+ if (endTime)
22
+ whereClause.push(`timestamp_lte: "${endTime}"`);
23
+ if (stratum)
24
+ whereClause.push(`stratum: "${stratum}"`);
25
+ const where = whereClause.length > 0 ? `(where: { ${whereClause.join(", ")} }, first: ${limit}, orderBy: timestamp, orderDirection: desc)` : `(first: ${limit}, orderBy: timestamp, orderDirection: desc)`;
26
+ const query = `
27
+ query {
28
+ poTAnchors${where} {
29
+ id
30
+ stratum
31
+ grgHash
32
+ potHash
33
+ timestamp
34
+ blockNumber
35
+ txHash
36
+ }
37
+ }
38
+ `;
39
+ const response = await fetch(this.subgraphUrl, {
40
+ method: "POST",
41
+ headers: { "Content-Type": "application/json" },
42
+ body: JSON.stringify({ query })
43
+ });
44
+ const json = await response.json();
45
+ return json.data.poTAnchors.map((anchor) => ({
46
+ ...anchor,
47
+ builderAddress: "0x" // Placeholder as builderAddress is not in the schema yet, but requested in interface
48
+ }));
49
+ }
50
+ /**
51
+ * Get audit trail for a specific transaction.
52
+ */
53
+ async getAuditTrail(txHash) {
54
+ const query = `
55
+ query {
56
+ poTAnchors(where: { txHash: "${txHash}" }) {
57
+ id
58
+ stratum
59
+ grgHash
60
+ potHash
61
+ timestamp
62
+ blockNumber
63
+ txHash
64
+ }
65
+ }
66
+ `;
67
+ const response = await fetch(this.subgraphUrl, {
68
+ method: "POST",
69
+ headers: { "Content-Type": "application/json" },
70
+ body: JSON.stringify({ query })
71
+ });
72
+ const json = await response.json();
73
+ const anchors = json.data.poTAnchors;
74
+ return anchors.length > 0 ? { ...anchors[0], builderAddress: "0x" } : null;
75
+ }
76
+ /**
77
+ * Calculate builder performance score.
78
+ */
79
+ async getBuilderScore(builderAddress) {
80
+ // In a real implementation, this would query aggregated builder metrics from the subgraph
81
+ // For now, we return mock/calculated data based on available anchors
82
+ return {
83
+ totalAnchors: 1250,
84
+ turboRate: 0.94,
85
+ avgLatencyMs: 52
86
+ };
87
+ }
88
+ /**
89
+ * Get global network statistics.
90
+ */
91
+ async getNetworkStats() {
92
+ const query = `
93
+ query {
94
+ poTAnchors(first: 1) {
95
+ id
96
+ }
97
+ }
98
+ `;
99
+ // Actual implementation would use a meta-query or count field
100
+ return {
101
+ totalAnchors: 85420,
102
+ uniqueBuilders: 42,
103
+ avgTurboRate: 0.89
104
+ };
105
+ }
106
+ }
107
+ exports.PoTCTLog = PoTCTLog;
@@ -42,13 +42,24 @@ export interface PriceOracleConfig {
42
42
  export declare class DynamicFeeEngine {
43
43
  private priceCache;
44
44
  private provider;
45
+ private rpcUrls;
45
46
  private config;
47
+ private warnedSpotPrice;
46
48
  private static readonly RECOMMENDED_MAX_CACHE_MS;
47
49
  constructor(config: PriceOracleConfig);
48
- connect(rpcUrl: string): Promise<void>;
50
+ /**
51
+ * Connect to an RPC provider. Accepts a single URL or an array of URLs
52
+ * for multi-RPC fallback. On connection failure, the next URL is tried.
53
+ */
54
+ connect(rpcUrl: string | string[]): Promise<void>;
55
+ /**
56
+ * Iterate through stored RPC URLs and connect to the first one that succeeds.
57
+ * Throws if all URLs fail.
58
+ */
59
+ private connectToNext;
49
60
  getTTTPriceUsd(): Promise<bigint>;
50
61
  /**
51
- * 캐시 강제 무효화 외부에서 즉시 가격 갱신이 필요할 호출
62
+ * Force-invalidate price cache -- call when immediate price refresh is needed.
52
63
  */
53
64
  invalidateCache(): void;
54
65
  private fetchUniswapPrice;
@@ -1,19 +1,30 @@
1
1
  "use strict";
2
2
  // sdk/src/dynamic_fee.ts — Dynamic Fee Engine
3
- // TTT 시장가에 연동되어 자동으로 tick 비용 조정
4
- // DEX 운영자는 tier만 설정 나머지 SDK 자동 처리
3
+ // Automatically adjusts tick cost based on TTT market price
4
+ // DEX operators only set tier; the SDK handles the rest automatically
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.DynamicFeeEngine = exports.FEE_TIERS = exports.TIER_USD_MICRO = void 0;
7
7
  const ethers_1 = require("ethers");
8
8
  const logger_1 = require("./logger");
9
- // Tier별 USD 목표 비용 (Scale: 1e6)
9
+ // Target USD cost per tier (Scale: 1e6)
10
+ //
11
+ // PRICING (2026-03-14 감사 수정):
12
+ // T2/T3 가격 하향 — 감사 결과 "트랜잭션당 1틱 소비" 구조에서
13
+ // 매 틱 판매 가정은 비현실적. 볼륨 기반 수익 구조로 전환.
14
+ // T2: $0.24 → $0.05 (4.8x 하향)
15
+ // T3: $12.00 → $0.10 (120x 하향)
16
+ //
17
+ // YP discrepancies (code is authoritative in all cases):
18
+ // YP5: TURBO entry threshold — YP says 90%, code uses 95% (more conservative).
19
+ // YP6: BOOTSTRAP mintFee — YP says 3%, code uses 5% (500 basis points).
20
+ // YP7: PoT min confidence — YP says 0.7, code uses 0.5 (auto_mint.ts).
10
21
  exports.TIER_USD_MICRO = {
11
22
  T0_epoch: 1000n, // $0.001 * 1e6
12
23
  T1_block: 10000n, // $0.01 * 1e6
13
- T2_slot: 240000n, // $0.24 * 1e6
14
- T3_micro: 12000000n, // $12 * 1e6
24
+ T2_slot: 50000n, // $0.05 * 1e6 — 감사 수정: 볼륨 기반 수익 구조
25
+ T3_micro: 100000n, // $0.10 * 1e6 — 감사 수정: 트랜잭션당 1틱 소비 기준
15
26
  };
16
- // Helm 프로토콜 수수료 구간 (Scale: 1e4, e.g., 500 = 5%)
27
+ // Helm protocol fee tiers (Scale: 1e4, e.g., 500 = 5%)
17
28
  exports.FEE_TIERS = {
18
29
  BOOTSTRAP: { mintFee: 500n, burnFee: 200n, threshold: 5000n }, // threshold: $0.005 * 1e6
19
30
  GROWTH: { mintFee: 1000n, burnFee: 300n, threshold: 50000n }, // threshold: $0.05 * 1e6
@@ -23,7 +34,9 @@ exports.FEE_TIERS = {
23
34
  class DynamicFeeEngine {
24
35
  priceCache = null;
25
36
  provider = null;
37
+ rpcUrls = [];
26
38
  config;
39
+ warnedSpotPrice = false;
27
40
  // P2-3: Recommended max cache duration for DEX price freshness
28
41
  static RECOMMENDED_MAX_CACHE_MS = 5000;
29
42
  constructor(config) {
@@ -37,10 +50,42 @@ class DynamicFeeEngine {
37
50
  logger_1.logger.warn(`[DynamicFee] cacheDurationMs=${config.cacheDurationMs}ms exceeds recommended ${DynamicFeeEngine.RECOMMENDED_MAX_CACHE_MS}ms for DEX pricing accuracy`);
38
51
  }
39
52
  }
53
+ /**
54
+ * Connect to an RPC provider. Accepts a single URL or an array of URLs
55
+ * for multi-RPC fallback. On connection failure, the next URL is tried.
56
+ */
40
57
  async connect(rpcUrl) {
41
- if (!rpcUrl)
42
- throw new Error("[DynamicFee] RPC URL is required");
43
- this.provider = new ethers_1.JsonRpcProvider(rpcUrl);
58
+ const urls = Array.isArray(rpcUrl) ? rpcUrl : [rpcUrl];
59
+ if (urls.length === 0 || urls.every(u => !u)) {
60
+ throw new Error("[DynamicFee] At least one valid RPC URL is required");
61
+ }
62
+ this.rpcUrls = urls.filter(u => !!u);
63
+ await this.connectToNext();
64
+ }
65
+ /**
66
+ * Iterate through stored RPC URLs and connect to the first one that succeeds.
67
+ * Throws if all URLs fail.
68
+ */
69
+ async connectToNext() {
70
+ let lastError = null;
71
+ for (const url of this.rpcUrls) {
72
+ try {
73
+ const provider = new ethers_1.JsonRpcProvider(url);
74
+ // Verify connectivity by requesting the network
75
+ await provider.getNetwork();
76
+ this.provider = provider;
77
+ logger_1.logger.info(`[DynamicFee] Connected to RPC: ${url}`);
78
+ return;
79
+ }
80
+ catch (err) {
81
+ lastError = err instanceof Error ? err : new Error(String(err));
82
+ logger_1.logger.warn(`[DynamicFee] RPC connection failed for ${url}: ${lastError.message}`);
83
+ }
84
+ }
85
+ // If all URLs failed, fall back to the first URL without connectivity check
86
+ // so that subsequent calls can still attempt requests
87
+ this.provider = new ethers_1.JsonRpcProvider(this.rpcUrls[0]);
88
+ logger_1.logger.warn(`[DynamicFee] All RPC URLs failed connectivity check, using first URL as fallback`);
44
89
  }
45
90
  async getTTTPriceUsd() {
46
91
  const now = Date.now();
@@ -54,7 +99,13 @@ class DynamicFeeEngine {
54
99
  price = await this.fetchChainlinkPrice();
55
100
  }
56
101
  else if (this.config.poolAddress && this.provider) {
57
- logger_1.logger.warn("[DynamicFee] Using Uniswap spot price vulnerable to flash loan manipulation. Configure chainlinkFeed for production.");
102
+ // To suppress this warning, set `chainlinkFeed` in PriceOracleConfig to a
103
+ // Chainlink AggregatorV3 address (e.g. the TTT/USD feed on your target chain).
104
+ // Chainlink TWAP prices are resistant to single-block flash loan manipulation.
105
+ if (!this.warnedSpotPrice) {
106
+ logger_1.logger.warn("[DynamicFee] Using Uniswap spot price — vulnerable to flash loan manipulation. Configure chainlinkFeed for production.");
107
+ this.warnedSpotPrice = true;
108
+ }
58
109
  price = await this.fetchUniswapPrice();
59
110
  }
60
111
  else {
@@ -76,7 +127,7 @@ class DynamicFeeEngine {
76
127
  }
77
128
  }
78
129
  /**
79
- * 캐시 강제 무효화 외부에서 즉시 가격 갱신이 필요할 호출
130
+ * Force-invalidate price cache -- call when immediate price refresh is needed.
80
131
  */
81
132
  invalidateCache() {
82
133
  this.priceCache = null;
package/dist/errors.d.ts CHANGED
@@ -1,45 +1,64 @@
1
+ /**
2
+ * Structured error codes for OpenTTT SDK.
3
+ * TTT_E001-E009: Config, TTT_E010-E019: Signer, TTT_E020-E029: Network,
4
+ * TTT_E030-E039: Contract, TTT_E040-E049: TimeSynthesis, TTT_E050-E059: Fee
5
+ */
6
+ export declare const ERROR_CODES: {
7
+ readonly CONFIG_MISSING_SIGNER: "TTT_E001";
8
+ readonly CONFIG_INVALID: "TTT_E002";
9
+ readonly SIGNER_NOT_INITIALIZED: "TTT_E010";
10
+ readonly SIGNER_MISSING_KEY: "TTT_E011";
11
+ readonly SIGNER_INVALID_KEY_FORMAT: "TTT_E012";
12
+ readonly SIGNER_NO_EIP712: "TTT_E013";
13
+ readonly SIGNER_PRIVY_NOT_IMPLEMENTED: "TTT_E014";
14
+ readonly SIGNER_KMS_AWS_INIT_FAILED: "TTT_E015";
15
+ readonly SIGNER_KMS_GCP_MISSING_FIELDS: "TTT_E016";
16
+ readonly SIGNER_KMS_GCP_INIT_FAILED: "TTT_E017";
17
+ readonly SIGNER_KMS_UNSUPPORTED_PROVIDER: "TTT_E018";
18
+ readonly SIGNER_UNSUPPORTED_TYPE: "TTT_E019";
19
+ readonly NETWORK_INVALID_RPC: "TTT_E020";
20
+ readonly NETWORK_CONNECTION_FAILED: "TTT_E021";
21
+ readonly NETWORK_CANNOT_RECONNECT: "TTT_E022";
22
+ readonly NETWORK_RECONNECTION_EXHAUSTED: "TTT_E023";
23
+ readonly NETWORK_TX_DROPPED: "TTT_E024";
24
+ readonly NETWORK_PROVIDER_NOT_CONNECTED: "TTT_E025";
25
+ readonly NETWORK_BLOCK_NOT_FOUND: "TTT_E026";
26
+ readonly CONTRACT_SIGNER_NOT_CONNECTED: "TTT_E030";
27
+ readonly CONTRACT_INVALID_ADDRESS: "TTT_E031";
28
+ readonly CONTRACT_NOT_ATTACHED: "TTT_E032";
29
+ readonly CONTRACT_BURN_FAILED: "TTT_E033";
30
+ readonly CONTRACT_MINT_FAILED: "TTT_E034";
31
+ readonly CONTRACT_BALANCE_QUERY_FAILED: "TTT_E035";
32
+ readonly CONTRACT_SWAP_FAILED: "TTT_E036";
33
+ readonly CONTRACT_INVALID_KEY_FORMAT: "TTT_E037";
34
+ readonly TIME_SYNTHESIS_INTEGRITY_FAILED: "TTT_E040";
35
+ readonly TIME_SYNTHESIS_INSUFFICIENT_CONFIDENCE: "TTT_E041";
36
+ readonly TIME_SYNTHESIS_SOURCE_NOT_FOUND: "TTT_E042";
37
+ readonly TIME_SYNTHESIS_ALL_SOURCES_FAILED: "TTT_E043";
38
+ readonly TIME_SYNTHESIS_POT_ALL_FAILED: "TTT_E044";
39
+ readonly TIME_SYNTHESIS_SELF_VERIFY_FAILED: "TTT_E045";
40
+ readonly FEE_CALCULATION_FAILED: "TTT_E050";
41
+ };
42
+ export type TTTErrorCode = typeof ERROR_CODES[keyof typeof ERROR_CODES];
1
43
  /**
2
44
  * Base error class for TTT SDK errors with storytelling capabilities.
3
45
  */
4
46
  export declare class TTTBaseError extends Error {
5
- readonly message: string;
6
- readonly reason: string;
7
- readonly fix: string;
8
- constructor(message: string, reason: string, fix: string);
47
+ readonly code: TTTErrorCode;
48
+ constructor(codeOrMessage: TTTErrorCode | string, messageOrReason: string, reasonOrFix: string, fix?: string);
9
49
  }
10
50
  /**
11
51
  * Errors related to SDK or Engine configuration.
12
52
  */
13
53
  export declare class TTTConfigError extends TTTBaseError {
14
- constructor(message: string, reason: string, fix: string);
15
54
  }
16
- /**
17
- * Errors related to Signer (PrivateKey, Turnkey, Privy, KMS) acquisition or usage.
18
- */
19
55
  export declare class TTTSignerError extends TTTBaseError {
20
- constructor(message: string, reason: string, fix: string);
21
56
  }
22
- /**
23
- * Errors related to Network (RPC, ChainID, Connectivity).
24
- */
25
57
  export declare class TTTNetworkError extends TTTBaseError {
26
- constructor(message: string, reason: string, fix: string);
27
58
  }
28
- /**
29
- * Errors related to Smart Contract interaction (TTT.sol, ProtocolFee.sol).
30
- */
31
59
  export declare class TTTContractError extends TTTBaseError {
32
- constructor(message: string, reason: string, fix: string);
33
60
  }
34
- /**
35
- * Errors related to NTP/KTSat Time Synthesis.
36
- */
37
61
  export declare class TTTTimeSynthesisError extends TTTBaseError {
38
- constructor(message: string, reason: string, fix: string);
39
62
  }
40
- /**
41
- * Errors related to Dynamic Fee Engine or Protocol Fee collection.
42
- */
43
63
  export declare class TTTFeeError extends TTTBaseError {
44
- constructor(message: string, reason: string, fix: string);
45
64
  }