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/errors.js CHANGED
@@ -1,18 +1,67 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TTTFeeError = exports.TTTTimeSynthesisError = exports.TTTContractError = exports.TTTNetworkError = exports.TTTSignerError = exports.TTTConfigError = exports.TTTBaseError = void 0;
3
+ exports.TTTFeeError = exports.TTTTimeSynthesisError = exports.TTTContractError = exports.TTTNetworkError = exports.TTTSignerError = exports.TTTConfigError = exports.TTTBaseError = exports.ERROR_CODES = void 0;
4
+ /**
5
+ * Structured error codes for OpenTTT SDK.
6
+ * TTT_E001-E009: Config, TTT_E010-E019: Signer, TTT_E020-E029: Network,
7
+ * TTT_E030-E039: Contract, TTT_E040-E049: TimeSynthesis, TTT_E050-E059: Fee
8
+ */
9
+ exports.ERROR_CODES = {
10
+ // Config errors (TTT_E001-E009)
11
+ CONFIG_MISSING_SIGNER: "TTT_E001",
12
+ CONFIG_INVALID: "TTT_E002",
13
+ // Signer errors (TTT_E010-E019)
14
+ SIGNER_NOT_INITIALIZED: "TTT_E010",
15
+ SIGNER_MISSING_KEY: "TTT_E011",
16
+ SIGNER_INVALID_KEY_FORMAT: "TTT_E012",
17
+ SIGNER_NO_EIP712: "TTT_E013",
18
+ SIGNER_PRIVY_NOT_IMPLEMENTED: "TTT_E014",
19
+ SIGNER_KMS_AWS_INIT_FAILED: "TTT_E015",
20
+ SIGNER_KMS_GCP_MISSING_FIELDS: "TTT_E016",
21
+ SIGNER_KMS_GCP_INIT_FAILED: "TTT_E017",
22
+ SIGNER_KMS_UNSUPPORTED_PROVIDER: "TTT_E018",
23
+ SIGNER_UNSUPPORTED_TYPE: "TTT_E019",
24
+ // Network errors (TTT_E020-E029)
25
+ NETWORK_INVALID_RPC: "TTT_E020",
26
+ NETWORK_CONNECTION_FAILED: "TTT_E021",
27
+ NETWORK_CANNOT_RECONNECT: "TTT_E022",
28
+ NETWORK_RECONNECTION_EXHAUSTED: "TTT_E023",
29
+ NETWORK_TX_DROPPED: "TTT_E024",
30
+ NETWORK_PROVIDER_NOT_CONNECTED: "TTT_E025",
31
+ NETWORK_BLOCK_NOT_FOUND: "TTT_E026",
32
+ // Contract errors (TTT_E030-E039)
33
+ CONTRACT_SIGNER_NOT_CONNECTED: "TTT_E030",
34
+ CONTRACT_INVALID_ADDRESS: "TTT_E031",
35
+ CONTRACT_NOT_ATTACHED: "TTT_E032",
36
+ CONTRACT_BURN_FAILED: "TTT_E033",
37
+ CONTRACT_MINT_FAILED: "TTT_E034",
38
+ CONTRACT_BALANCE_QUERY_FAILED: "TTT_E035",
39
+ CONTRACT_SWAP_FAILED: "TTT_E036",
40
+ CONTRACT_INVALID_KEY_FORMAT: "TTT_E037",
41
+ // TimeSynthesis errors (TTT_E040-E049)
42
+ TIME_SYNTHESIS_INTEGRITY_FAILED: "TTT_E040",
43
+ TIME_SYNTHESIS_INSUFFICIENT_CONFIDENCE: "TTT_E041",
44
+ TIME_SYNTHESIS_SOURCE_NOT_FOUND: "TTT_E042",
45
+ TIME_SYNTHESIS_ALL_SOURCES_FAILED: "TTT_E043",
46
+ TIME_SYNTHESIS_POT_ALL_FAILED: "TTT_E044",
47
+ TIME_SYNTHESIS_SELF_VERIFY_FAILED: "TTT_E045",
48
+ // Fee errors (TTT_E050-E059)
49
+ FEE_CALCULATION_FAILED: "TTT_E050",
50
+ };
4
51
  /**
5
52
  * Base error class for TTT SDK errors with storytelling capabilities.
6
53
  */
7
54
  class TTTBaseError extends Error {
8
- message;
9
- reason;
10
- fix;
11
- constructor(message, reason, fix) {
12
- super(`${message} (Reason: ${reason}. Fix: ${fix})`);
13
- this.message = message;
14
- this.reason = reason;
15
- this.fix = fix;
55
+ code;
56
+ constructor(codeOrMessage, messageOrReason, reasonOrFix, fix) {
57
+ // Support both old (message, reason, fix) and new (code, message, reason, fix) signatures
58
+ const hasCode = fix !== undefined;
59
+ const code = hasCode ? codeOrMessage : "TTT_E002";
60
+ const message = hasCode ? messageOrReason : codeOrMessage;
61
+ const reason = hasCode ? reasonOrFix : messageOrReason;
62
+ const fixStr = hasCode ? fix : reasonOrFix;
63
+ super(`[${code}] ${message} (Reason: ${reason}. Fix: ${fixStr})`);
64
+ this.code = code;
16
65
  this.name = this.constructor.name;
17
66
  Object.setPrototypeOf(this, new.target.prototype);
18
67
  }
@@ -22,53 +71,20 @@ exports.TTTBaseError = TTTBaseError;
22
71
  * Errors related to SDK or Engine configuration.
23
72
  */
24
73
  class TTTConfigError extends TTTBaseError {
25
- constructor(message, reason, fix) {
26
- super(message, reason, fix);
27
- }
28
74
  }
29
75
  exports.TTTConfigError = TTTConfigError;
30
- /**
31
- * Errors related to Signer (PrivateKey, Turnkey, Privy, KMS) acquisition or usage.
32
- */
33
76
  class TTTSignerError extends TTTBaseError {
34
- constructor(message, reason, fix) {
35
- super(message, reason, fix);
36
- }
37
77
  }
38
78
  exports.TTTSignerError = TTTSignerError;
39
- /**
40
- * Errors related to Network (RPC, ChainID, Connectivity).
41
- */
42
79
  class TTTNetworkError extends TTTBaseError {
43
- constructor(message, reason, fix) {
44
- super(message, reason, fix);
45
- }
46
80
  }
47
81
  exports.TTTNetworkError = TTTNetworkError;
48
- /**
49
- * Errors related to Smart Contract interaction (TTT.sol, ProtocolFee.sol).
50
- */
51
82
  class TTTContractError extends TTTBaseError {
52
- constructor(message, reason, fix) {
53
- super(message, reason, fix);
54
- }
55
83
  }
56
84
  exports.TTTContractError = TTTContractError;
57
- /**
58
- * Errors related to NTP/KTSat Time Synthesis.
59
- */
60
85
  class TTTTimeSynthesisError extends TTTBaseError {
61
- constructor(message, reason, fix) {
62
- super(message, reason, fix);
63
- }
64
86
  }
65
87
  exports.TTTTimeSynthesisError = TTTTimeSynthesisError;
66
- /**
67
- * Errors related to Dynamic Fee Engine or Protocol Fee collection.
68
- */
69
88
  class TTTFeeError extends TTTBaseError {
70
- constructor(message, reason, fix) {
71
- super(message, reason, fix);
72
- }
73
89
  }
74
90
  exports.TTTFeeError = TTTFeeError;
@@ -7,6 +7,10 @@ export interface VerificationResult {
7
7
  txCount: number;
8
8
  latency: number;
9
9
  }
10
+ export interface EVMConnectorOptions {
11
+ fallbackRpcUrls?: string[];
12
+ maxReconnectAttempts?: number;
13
+ }
10
14
  export declare class EVMConnector {
11
15
  private provider;
12
16
  private signer;
@@ -14,7 +18,12 @@ export declare class EVMConnector {
14
18
  private protocolFeeContract;
15
19
  private eventListeners;
16
20
  private static readonly GAS_TIMEOUT_MS;
17
- constructor();
21
+ private primaryRpcUrl;
22
+ private fallbackRpcUrls;
23
+ private signerOrKey;
24
+ private maxReconnectAttempts;
25
+ private connected;
26
+ constructor(options?: EVMConnectorOptions);
18
27
  /**
19
28
  * P1-7: Race estimateGas against timeout to prevent DoS
20
29
  */
@@ -23,6 +32,24 @@ export declare class EVMConnector {
23
32
  * Connect to an EVM chain using either a private key or a pre-configured signer.
24
33
  */
25
34
  connect(rpcUrl: string, signerOrKey: string | Signer): Promise<void>;
35
+ /**
36
+ * Reconnect using stored credentials. Tries primary first, then fallbacks.
37
+ */
38
+ reconnect(): Promise<void>;
39
+ /**
40
+ * Disconnect and release all resources.
41
+ */
42
+ disconnect(): void;
43
+ /**
44
+ * Check if the connector is currently connected.
45
+ */
46
+ isConnected(): boolean;
47
+ /**
48
+ * CT Log Equivalent: PoTAnchored event ABI fragment.
49
+ * Every Proof-of-Time anchor is publicly auditable on-chain,
50
+ * analogous to Certificate Transparency logs in TLS.
51
+ */
52
+ static readonly POT_ANCHORED_EVENT_ABI = "event PoTAnchored(uint64 indexed timestamp, bytes32 grgHash, uint8 stratum, bytes32 potHash)";
26
53
  /**
27
54
  * Attach the TTT Token contract.
28
55
  */
@@ -14,14 +14,22 @@ class EVMConnector {
14
14
  eventListeners = []; // P2-6: Track listeners for cleanup
15
15
  // P1-7: Timeout wrapper for gas estimation
16
16
  static GAS_TIMEOUT_MS = 5000;
17
- constructor() { }
17
+ primaryRpcUrl = "";
18
+ fallbackRpcUrls = [];
19
+ signerOrKey = null;
20
+ maxReconnectAttempts;
21
+ connected = false;
22
+ constructor(options) {
23
+ this.fallbackRpcUrls = options?.fallbackRpcUrls ?? [];
24
+ this.maxReconnectAttempts = options?.maxReconnectAttempts ?? 3;
25
+ }
18
26
  /**
19
27
  * P1-7: Race estimateGas against timeout to prevent DoS
20
28
  */
21
29
  async withTimeout(promise, ms = EVMConnector.GAS_TIMEOUT_MS) {
22
30
  return Promise.race([
23
31
  promise,
24
- new Promise((_, reject) => setTimeout(() => reject(new errors_1.TTTNetworkError(`[EVM] Operation timed out`, `RPC did not respond within ${ms}ms`, `Check your RPC provider status or increase timeout.`)), ms))
32
+ new Promise((_, reject) => setTimeout(() => reject(new errors_1.TTTNetworkError(errors_1.ERROR_CODES.NETWORK_CONNECTION_FAILED, `[EVM] Operation timed out`, `RPC did not respond within ${ms}ms`, `Check your RPC provider status or increase timeout.`)), ms))
25
33
  ]);
26
34
  }
27
35
  /**
@@ -29,36 +37,116 @@ class EVMConnector {
29
37
  */
30
38
  async connect(rpcUrl, signerOrKey) {
31
39
  if (!rpcUrl || typeof rpcUrl !== "string")
32
- throw new errors_1.TTTNetworkError("[EVM] Invalid RPC URL", "The provided RPC URL is empty or not a string", "Pass a valid RPC URL (e.g., https://mainnet.base.org)");
40
+ throw new errors_1.TTTNetworkError(errors_1.ERROR_CODES.NETWORK_INVALID_RPC, "[EVM] Invalid RPC URL", "The provided RPC URL is empty or not a string", "Pass a valid RPC URL (e.g., https://mainnet.base.org)");
41
+ this.primaryRpcUrl = rpcUrl;
42
+ this.signerOrKey = signerOrKey;
33
43
  try {
34
44
  this.provider = new ethers_1.JsonRpcProvider(rpcUrl);
35
45
  if (typeof signerOrKey === "string") {
36
46
  if (!signerOrKey.startsWith("0x") || signerOrKey.length !== 66) {
37
- throw new errors_1.TTTContractError("[EVM] Invalid Private Key format", "Private key must be 0x + 64 hex characters", "Provide a valid 32-byte hex private key.");
47
+ throw new errors_1.TTTContractError(errors_1.ERROR_CODES.CONTRACT_INVALID_KEY_FORMAT, "[EVM] Invalid Private Key format", "Private key must be 0x + 64 hex characters", "Provide a valid 32-byte hex private key.");
38
48
  }
39
49
  this.signer = new ethers_1.ethers.Wallet(signerOrKey, this.provider);
40
50
  }
41
51
  else {
42
- // Signer might already be connected to a provider, but we ensure it's linked to ours
43
52
  this.signer = signerOrKey.connect ? signerOrKey.connect(this.provider) : signerOrKey;
44
53
  }
45
54
  const network = await this.provider.getNetwork();
55
+ this.connected = true;
46
56
  logger_1.logger.info(`[EVM] Connected to Chain ID: ${network.chainId}`);
47
57
  }
48
58
  catch (error) {
49
59
  if (error instanceof errors_1.TTTContractError || error instanceof errors_1.TTTNetworkError)
50
60
  throw error;
51
- throw new errors_1.TTTNetworkError(`[EVM] Connection failed`, error instanceof Error ? error.message : String(error), `Verify your RPC URL and network connectivity.`);
61
+ // Try fallback RPCs before giving up
62
+ for (const fallback of this.fallbackRpcUrls) {
63
+ try {
64
+ logger_1.logger.warn(`[EVM] Primary RPC failed, trying fallback: ${fallback}`);
65
+ this.provider = new ethers_1.JsonRpcProvider(fallback);
66
+ if (typeof signerOrKey === "string") {
67
+ this.signer = new ethers_1.ethers.Wallet(signerOrKey, this.provider);
68
+ }
69
+ else {
70
+ this.signer = signerOrKey.connect ? signerOrKey.connect(this.provider) : signerOrKey;
71
+ }
72
+ const network = await this.provider.getNetwork();
73
+ this.connected = true;
74
+ logger_1.logger.info(`[EVM] Connected via fallback to Chain ID: ${network.chainId}`);
75
+ return;
76
+ }
77
+ catch {
78
+ continue;
79
+ }
80
+ }
81
+ throw new errors_1.TTTNetworkError(errors_1.ERROR_CODES.NETWORK_CONNECTION_FAILED, `[EVM] Connection failed`, error instanceof Error ? error.message : String(error), `Verify your RPC URL and network connectivity.`);
82
+ }
83
+ }
84
+ /**
85
+ * Reconnect using stored credentials. Tries primary first, then fallbacks.
86
+ */
87
+ async reconnect() {
88
+ if (!this.signerOrKey)
89
+ throw new errors_1.TTTNetworkError(errors_1.ERROR_CODES.NETWORK_CANNOT_RECONNECT, "[EVM] Cannot reconnect", "No previous connection credentials stored", "Call connect() first.");
90
+ this.disconnect();
91
+ const allUrls = [this.primaryRpcUrl, ...this.fallbackRpcUrls].filter(Boolean);
92
+ for (let attempt = 0; attempt < Math.min(this.maxReconnectAttempts, allUrls.length); attempt++) {
93
+ try {
94
+ const url = allUrls[attempt % allUrls.length];
95
+ logger_1.logger.info(`[EVM] Reconnect attempt ${attempt + 1}/${this.maxReconnectAttempts} → ${url}`);
96
+ this.provider = new ethers_1.JsonRpcProvider(url);
97
+ if (typeof this.signerOrKey === "string") {
98
+ this.signer = new ethers_1.ethers.Wallet(this.signerOrKey, this.provider);
99
+ }
100
+ else {
101
+ this.signer = this.signerOrKey.connect ? this.signerOrKey.connect(this.provider) : this.signerOrKey;
102
+ }
103
+ await this.provider.getNetwork();
104
+ this.connected = true;
105
+ logger_1.logger.info(`[EVM] Reconnected successfully`);
106
+ return;
107
+ }
108
+ catch {
109
+ logger_1.logger.warn(`[EVM] Reconnect attempt ${attempt + 1} failed`);
110
+ }
111
+ }
112
+ this.connected = false;
113
+ throw new errors_1.TTTNetworkError(errors_1.ERROR_CODES.NETWORK_RECONNECTION_EXHAUSTED, "[EVM] Reconnection failed", `All ${this.maxReconnectAttempts} attempts exhausted`, "Check RPC provider status and network connectivity.");
114
+ }
115
+ /**
116
+ * Disconnect and release all resources.
117
+ */
118
+ disconnect() {
119
+ this.unsubscribeAll();
120
+ if (this.provider) {
121
+ this.provider.destroy();
52
122
  }
123
+ this.provider = null;
124
+ this.signer = null;
125
+ this.tttContract = null;
126
+ this.protocolFeeContract = null;
127
+ this.connected = false;
128
+ logger_1.logger.info("[EVM] Disconnected and resources released");
129
+ }
130
+ /**
131
+ * Check if the connector is currently connected.
132
+ */
133
+ isConnected() {
134
+ return this.connected && this.provider !== null;
53
135
  }
136
+ /**
137
+ * CT Log Equivalent: PoTAnchored event ABI fragment.
138
+ * Every Proof-of-Time anchor is publicly auditable on-chain,
139
+ * analogous to Certificate Transparency logs in TLS.
140
+ */
141
+ static POT_ANCHORED_EVENT_ABI = "event PoTAnchored(uint64 indexed timestamp, bytes32 grgHash, uint8 stratum, bytes32 potHash)";
54
142
  /**
55
143
  * Attach the TTT Token contract.
56
144
  */
57
145
  attachContract(address, abi) {
58
146
  if (!this.signer)
59
- throw new errors_1.TTTContractError("Not connected to signer", "EVMConnector.connect() must be called first", "Initialize connection before attaching contracts.");
147
+ throw new errors_1.TTTContractError(errors_1.ERROR_CODES.CONTRACT_SIGNER_NOT_CONNECTED, "Not connected to signer", "EVMConnector.connect() must be called first", "Initialize connection before attaching contracts.");
60
148
  if (!address || !ethers_1.ethers.isAddress(address))
61
- throw new errors_1.TTTContractError(`[EVM] Invalid contract address`, `Address '${address}' is not a valid EVM address`, `Check your config and provide a valid checksummed address.`);
149
+ throw new errors_1.TTTContractError(errors_1.ERROR_CODES.CONTRACT_INVALID_ADDRESS, `[EVM] Invalid contract address`, `Address '${address}' is not a valid EVM address`, `Check your config and provide a valid checksummed address.`);
62
150
  this.tttContract = new ethers_1.Contract(address, abi, this.signer);
63
151
  }
64
152
  /**
@@ -66,9 +154,9 @@ class EVMConnector {
66
154
  */
67
155
  attachProtocolFeeContract(address, abi) {
68
156
  if (!this.signer)
69
- throw new errors_1.TTTContractError("Not connected to signer", "EVMConnector.connect() must be called first", "Initialize connection before attaching contracts.");
157
+ throw new errors_1.TTTContractError(errors_1.ERROR_CODES.CONTRACT_SIGNER_NOT_CONNECTED, "Not connected to signer", "EVMConnector.connect() must be called first", "Initialize connection before attaching contracts.");
70
158
  if (!address || !ethers_1.ethers.isAddress(address))
71
- throw new errors_1.TTTContractError(`[EVM] Invalid contract address`, `Address '${address}' is not a valid EVM address`, `Check your config and provide a valid checksummed address.`);
159
+ throw new errors_1.TTTContractError(errors_1.ERROR_CODES.CONTRACT_INVALID_ADDRESS, `[EVM] Invalid contract address`, `Address '${address}' is not a valid EVM address`, `Check your config and provide a valid checksummed address.`);
72
160
  this.protocolFeeContract = new ethers_1.Contract(address, abi, this.signer);
73
161
  }
74
162
  /**
@@ -76,7 +164,7 @@ class EVMConnector {
76
164
  */
77
165
  async submitTTTRecord(record, amount, tier) {
78
166
  if (!this.tttContract)
79
- throw new errors_1.TTTContractError("Contract not attached", "TTT contract instance is null", "Call attachContract() with valid TTT address before burning.");
167
+ throw new errors_1.TTTContractError(errors_1.ERROR_CODES.CONTRACT_NOT_ATTACHED, "Contract not attached", "TTT contract instance is null", "Call attachContract() with valid TTT address before burning.");
80
168
  const grgHash = ethers_1.ethers.keccak256(ethers_1.ethers.concat(record.grgPayload));
81
169
  try {
82
170
  // P1-7: Gas estimation with timeout
@@ -88,14 +176,14 @@ class EVMConnector {
88
176
  const receipt = await tx.wait();
89
177
  // P2-5: Null check for dropped transactions
90
178
  if (!receipt)
91
- throw new errors_1.TTTNetworkError(`[EVM] Transaction failed`, `Transaction was dropped from mempool or null receipt`, `Check block explorer for tx status.`);
179
+ throw new errors_1.TTTNetworkError(errors_1.ERROR_CODES.NETWORK_TX_DROPPED, `[EVM] Transaction failed`, `Transaction was dropped from mempool or null receipt`, `Check block explorer for tx status.`);
92
180
  return receipt;
93
181
  }
94
182
  catch (error) {
95
183
  if (error instanceof errors_1.TTTNetworkError || error instanceof errors_1.TTTContractError)
96
184
  throw error;
97
185
  const reason = this.extractRevertReason(error);
98
- throw new errors_1.TTTContractError(`[EVM] Burn failed`, reason, `Verify your TTT balance and tier parameters.`);
186
+ throw new errors_1.TTTContractError(errors_1.ERROR_CODES.CONTRACT_BURN_FAILED, `[EVM] Burn failed`, reason, `Verify your TTT balance and tier parameters.`);
99
187
  }
100
188
  }
101
189
  /**
@@ -103,22 +191,26 @@ class EVMConnector {
103
191
  */
104
192
  async mintTTT(to, amount, grgHash, potHash) {
105
193
  if (!this.tttContract)
106
- throw new errors_1.TTTContractError("Contract not attached", "TTT contract instance is null", "Call attachContract() before minting.");
194
+ throw new errors_1.TTTContractError(errors_1.ERROR_CODES.CONTRACT_NOT_ATTACHED, "Contract not attached", "TTT contract instance is null", "Call attachContract() before minting.");
107
195
  if (!to || !ethers_1.ethers.isAddress(to))
108
- throw new errors_1.TTTContractError(`[EVM] Invalid recipient address`, `Address '${to}' is not a valid EVM address`, `Provide a valid destination address.`);
196
+ throw new errors_1.TTTContractError(errors_1.ERROR_CODES.CONTRACT_INVALID_ADDRESS, `[EVM] Invalid recipient address`, `Address '${to}' is not a valid EVM address`, `Provide a valid destination address.`);
109
197
  try {
110
198
  if (potHash) {
111
199
  logger_1.logger.info(`[EVM] Recording PoT fingerprint: ${potHash}`);
112
200
  }
113
- const tx = await this.tttContract.mint(to, amount, grgHash);
201
+ // Gas estimation with 20% buffer and timeout (matching burnTTT pattern)
202
+ const gasLimit = await this.withTimeout(this.tttContract.mint.estimateGas(to, amount, grgHash));
203
+ const tx = await this.tttContract.mint(to, amount, grgHash, {
204
+ gasLimit: (gasLimit * 120n) / 100n
205
+ });
114
206
  const receipt = await tx.wait();
115
207
  if (!receipt)
116
- throw new errors_1.TTTNetworkError(`[EVM] Mint TX dropped`, `Transaction was dropped from mempool`, `Check operator account for nonce collisions.`);
208
+ throw new errors_1.TTTNetworkError(errors_1.ERROR_CODES.NETWORK_TX_DROPPED, `[EVM] Mint TX dropped`, `Transaction was dropped from mempool`, `Check operator account for nonce collisions.`);
117
209
  return receipt;
118
210
  }
119
211
  catch (error) {
120
212
  const reason = this.extractRevertReason(error);
121
- throw new errors_1.TTTContractError(`[EVM] Mint failed`, reason, `Ensure operator has minter role and sufficient gas.`);
213
+ throw new errors_1.TTTContractError(errors_1.ERROR_CODES.CONTRACT_MINT_FAILED, `[EVM] Mint failed`, reason, `Ensure operator has minter role and sufficient gas.`);
122
214
  }
123
215
  }
124
216
  /**
@@ -126,17 +218,17 @@ class EVMConnector {
126
218
  */
127
219
  async burnTTT(amount, grgHash, tierLevel) {
128
220
  if (!this.tttContract)
129
- throw new errors_1.TTTContractError("Contract not attached", "TTT contract instance is null", "Call attachContract() before burning.");
221
+ throw new errors_1.TTTContractError(errors_1.ERROR_CODES.CONTRACT_NOT_ATTACHED, "Contract not attached", "TTT contract instance is null", "Call attachContract() before burning.");
130
222
  try {
131
223
  const tx = await this.tttContract.burn(amount, grgHash, tierLevel);
132
224
  const receipt = await tx.wait();
133
225
  if (!receipt)
134
- throw new errors_1.TTTNetworkError(`[EVM] Burn TX dropped`, `Transaction was dropped from mempool`, `Verify account balance.`);
226
+ throw new errors_1.TTTNetworkError(errors_1.ERROR_CODES.NETWORK_TX_DROPPED, `[EVM] Burn TX dropped`, `Transaction was dropped from mempool`, `Verify account balance.`);
135
227
  return { hash: receipt.hash };
136
228
  }
137
229
  catch (error) {
138
230
  const reason = this.extractRevertReason(error);
139
- throw new errors_1.TTTContractError(`[EVM] Burn failed`, reason, `Check TTT balance.`);
231
+ throw new errors_1.TTTContractError(errors_1.ERROR_CODES.CONTRACT_BURN_FAILED, `[EVM] Burn failed`, reason, `Check TTT balance.`);
140
232
  }
141
233
  }
142
234
  /**
@@ -144,13 +236,13 @@ class EVMConnector {
144
236
  */
145
237
  async getTTTBalance(user, tokenId) {
146
238
  if (!this.tttContract)
147
- throw new errors_1.TTTContractError("Contract not attached", "TTT contract instance is null", "Call attachContract() before querying balance.");
239
+ throw new errors_1.TTTContractError(errors_1.ERROR_CODES.CONTRACT_NOT_ATTACHED, "Contract not attached", "TTT contract instance is null", "Call attachContract() before querying balance.");
148
240
  try {
149
241
  return await this.tttContract.balanceOf(user, tokenId);
150
242
  }
151
243
  catch (error) {
152
244
  const reason = this.extractRevertReason(error);
153
- throw new errors_1.TTTContractError(`[EVM] Balance query failed`, reason, `Check RPC connection and contract address.`);
245
+ throw new errors_1.TTTContractError(errors_1.ERROR_CODES.CONTRACT_BALANCE_QUERY_FAILED, `[EVM] Balance query failed`, reason, `Check RPC connection and contract address.`);
154
246
  }
155
247
  }
156
248
  /**
@@ -158,9 +250,9 @@ class EVMConnector {
158
250
  */
159
251
  async swap(routerAddress, tokenIn, tokenOut, amountIn, minAmountOut) {
160
252
  if (!this.signer)
161
- throw new errors_1.TTTContractError("Not connected to signer", "Signer is null", "Initialize connection.");
253
+ throw new errors_1.TTTContractError(errors_1.ERROR_CODES.CONTRACT_SIGNER_NOT_CONNECTED, "Not connected to signer", "Signer is null", "Initialize connection.");
162
254
  if (!routerAddress || !ethers_1.ethers.isAddress(routerAddress))
163
- throw new errors_1.TTTContractError(`[EVM] Invalid router address`, `Address '${routerAddress}' is invalid`, `Provide valid V4 SwapRouter address.`);
255
+ throw new errors_1.TTTContractError(errors_1.ERROR_CODES.CONTRACT_INVALID_ADDRESS, `[EVM] Invalid router address`, `Address '${routerAddress}' is invalid`, `Provide valid V4 SwapRouter address.`);
164
256
  logger_1.logger.info(`[EVM] Swapping ${amountIn} of ${tokenIn} for ${tokenOut} via ${routerAddress}`);
165
257
  // Realistic Uniswap V4-like SwapRouter ABI for simulation/integration
166
258
  const swapRouterAbi = [
@@ -176,14 +268,14 @@ class EVMConnector {
176
268
  logger_1.logger.info(`[EVM] Swap TX Sent: ${tx.hash}`);
177
269
  const receipt = await tx.wait();
178
270
  if (!receipt)
179
- throw new errors_1.TTTNetworkError(`[EVM] Swap TX dropped`, `Transaction dropped`, `Check gas price.`);
271
+ throw new errors_1.TTTNetworkError(errors_1.ERROR_CODES.NETWORK_TX_DROPPED, `[EVM] Swap TX dropped`, `Transaction dropped`, `Check gas price.`);
180
272
  return receipt;
181
273
  }
182
274
  catch (error) {
183
275
  if (error instanceof errors_1.TTTNetworkError || error instanceof errors_1.TTTContractError)
184
276
  throw error;
185
277
  const reason = this.extractRevertReason(error);
186
- throw new errors_1.TTTContractError(`[EVM] Swap failed`, reason, `Verify slippage and token balances.`);
278
+ throw new errors_1.TTTContractError(errors_1.ERROR_CODES.CONTRACT_SWAP_FAILED, `[EVM] Swap failed`, reason, `Verify slippage and token balances.`);
187
279
  }
188
280
  }
189
281
  /**
@@ -241,10 +333,10 @@ class EVMConnector {
241
333
  */
242
334
  async verifyBlock(blockNum) {
243
335
  if (!this.provider)
244
- throw new errors_1.TTTNetworkError("Provider not connected", "RPC provider is null", "Call connect() first.");
336
+ throw new errors_1.TTTNetworkError(errors_1.ERROR_CODES.NETWORK_PROVIDER_NOT_CONNECTED, "Provider not connected", "RPC provider is null", "Call connect() first.");
245
337
  const block = await this.provider.getBlock(blockNum);
246
338
  if (!block)
247
- throw new errors_1.TTTNetworkError(`Block not found`, `RPC returned null for block ${blockNum}`, `Verify if block number exists on chain.`);
339
+ throw new errors_1.TTTNetworkError(errors_1.ERROR_CODES.NETWORK_BLOCK_NOT_FOUND, `Block not found`, `RPC returned null for block ${blockNum}`, `Verify if block number exists on chain.`);
248
340
  return {
249
341
  valid: true,
250
342
  blockNumber: blockNum,
@@ -258,7 +350,7 @@ class EVMConnector {
258
350
  */
259
351
  async getPendingTransactions() {
260
352
  if (!this.provider)
261
- throw new errors_1.TTTNetworkError("Provider not connected", "RPC provider is null", "Call connect() first.");
353
+ throw new errors_1.TTTNetworkError(errors_1.ERROR_CODES.NETWORK_PROVIDER_NOT_CONNECTED, "Provider not connected", "RPC provider is null", "Call connect() first.");
262
354
  const block = await this.provider.send("eth_getBlockByNumber", ["pending", false]);
263
355
  return block ? block.transactions : [];
264
356
  }
@@ -267,7 +359,7 @@ class EVMConnector {
267
359
  */
268
360
  getProvider() {
269
361
  if (!this.provider)
270
- throw new errors_1.TTTNetworkError("Provider not connected", "RPC provider is null", "Call connect() first.");
362
+ throw new errors_1.TTTNetworkError(errors_1.ERROR_CODES.NETWORK_PROVIDER_NOT_CONNECTED, "Provider not connected", "RPC provider is null", "Call connect() first.");
271
363
  return this.provider;
272
364
  }
273
365
  /**
@@ -275,7 +367,7 @@ class EVMConnector {
275
367
  */
276
368
  getSigner() {
277
369
  if (!this.signer)
278
- throw new errors_1.TTTContractError("Signer not connected", "Signer is null", "Call connect() first.");
370
+ throw new errors_1.TTTContractError(errors_1.ERROR_CODES.CONTRACT_SIGNER_NOT_CONNECTED, "Signer not connected", "Signer is null", "Call connect() first.");
279
371
  return this.signer;
280
372
  }
281
373
  /**
@@ -0,0 +1,41 @@
1
+ /**
2
+ * GRG API Client — replaces local GRG computation with server-side API call.
3
+ * GRG source code stays in Helm private repo. Only API calls go through npm SDK.
4
+ *
5
+ * Drop-in replacement interface for local GrgForward.encode() and GrgInverse.verify().
6
+ */
7
+ export interface GrgEncodeResult {
8
+ /** Hex-encoded serialized shards (joined as JSON array of hex strings) */
9
+ shards: string[];
10
+ }
11
+ export interface GrgVerifyResult {
12
+ valid: boolean;
13
+ }
14
+ export declare class GrgApiClient {
15
+ private baseUrl;
16
+ private timeoutMs;
17
+ constructor(baseUrl?: string, options?: {
18
+ timeoutMs?: number;
19
+ });
20
+ /**
21
+ * Forward pass: encode data through GRG pipeline (server-side).
22
+ * Same interface contract as local GrgForward.encode().
23
+ *
24
+ * @returns Array of Uint8Array shards (same shape as GrgForward.encode())
25
+ */
26
+ encode(data: Uint8Array, chainId: number, poolAddress: string): Promise<Uint8Array[]>;
27
+ /**
28
+ * Verify: check GRG integrity (server-side).
29
+ * Same interface contract as local GrgInverse.verify().
30
+ *
31
+ * @returns boolean — true if data matches the original shards
32
+ */
33
+ verify(data: Uint8Array, originalShards: Uint8Array[], chainId: number, poolAddress: string): Promise<boolean>;
34
+ /**
35
+ * Health check — ping the GRG API server.
36
+ * Returns true if reachable within timeoutMs.
37
+ */
38
+ isReachable(): Promise<boolean>;
39
+ }
40
+ export declare function getDefaultGrgApiClient(): GrgApiClient;
41
+ export declare function setDefaultGrgApiClient(client: GrgApiClient): void;
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ /**
3
+ * GRG API Client — replaces local GRG computation with server-side API call.
4
+ * GRG source code stays in Helm private repo. Only API calls go through npm SDK.
5
+ *
6
+ * Drop-in replacement interface for local GrgForward.encode() and GrgInverse.verify().
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.GrgApiClient = void 0;
10
+ exports.getDefaultGrgApiClient = getDefaultGrgApiClient;
11
+ exports.setDefaultGrgApiClient = setDefaultGrgApiClient;
12
+ class GrgApiClient {
13
+ baseUrl;
14
+ timeoutMs;
15
+ constructor(baseUrl = "https://grg.helmprotocol.com/api/v1", options) {
16
+ this.baseUrl = baseUrl.replace(/\/$/, "");
17
+ this.timeoutMs = options?.timeoutMs ?? 5000;
18
+ }
19
+ /**
20
+ * Forward pass: encode data through GRG pipeline (server-side).
21
+ * Same interface contract as local GrgForward.encode().
22
+ *
23
+ * @returns Array of Uint8Array shards (same shape as GrgForward.encode())
24
+ */
25
+ async encode(data, chainId, poolAddress) {
26
+ const controller = new AbortController();
27
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
28
+ try {
29
+ const resp = await fetch(`${this.baseUrl}/encode`, {
30
+ method: "POST",
31
+ headers: { "Content-Type": "application/json" },
32
+ body: JSON.stringify({
33
+ data: Buffer.from(data).toString("hex"),
34
+ chainId: chainId,
35
+ poolAddress,
36
+ }),
37
+ signal: controller.signal,
38
+ });
39
+ if (!resp.ok) {
40
+ throw new Error(`GRG API error: ${resp.status} ${resp.statusText}`);
41
+ }
42
+ const result = await resp.json();
43
+ return result.shards.map((hex) => Buffer.from(hex, "hex"));
44
+ }
45
+ finally {
46
+ clearTimeout(timer);
47
+ }
48
+ }
49
+ /**
50
+ * Verify: check GRG integrity (server-side).
51
+ * Same interface contract as local GrgInverse.verify().
52
+ *
53
+ * @returns boolean — true if data matches the original shards
54
+ */
55
+ async verify(data, originalShards, chainId, poolAddress) {
56
+ const controller = new AbortController();
57
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
58
+ try {
59
+ const resp = await fetch(`${this.baseUrl}/verify`, {
60
+ method: "POST",
61
+ headers: { "Content-Type": "application/json" },
62
+ body: JSON.stringify({
63
+ data: Buffer.from(data).toString("hex"),
64
+ shards: originalShards.map((s) => Buffer.from(s).toString("hex")),
65
+ chainId: chainId,
66
+ poolAddress,
67
+ }),
68
+ signal: controller.signal,
69
+ });
70
+ if (!resp.ok) {
71
+ throw new Error(`GRG API error: ${resp.status} ${resp.statusText}`);
72
+ }
73
+ const result = await resp.json();
74
+ return result.valid;
75
+ }
76
+ finally {
77
+ clearTimeout(timer);
78
+ }
79
+ }
80
+ /**
81
+ * Health check — ping the GRG API server.
82
+ * Returns true if reachable within timeoutMs.
83
+ */
84
+ async isReachable() {
85
+ const controller = new AbortController();
86
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
87
+ try {
88
+ const resp = await fetch(`${this.baseUrl}/health`, {
89
+ method: "GET",
90
+ signal: controller.signal,
91
+ });
92
+ return resp.ok;
93
+ }
94
+ catch {
95
+ return false;
96
+ }
97
+ finally {
98
+ clearTimeout(timer);
99
+ }
100
+ }
101
+ }
102
+ exports.GrgApiClient = GrgApiClient;
103
+ /**
104
+ * Singleton default client — uses production GRG API endpoint.
105
+ * Can be overridden via setDefaultGrgApiClient() for testing/staging.
106
+ */
107
+ let _defaultClient = null;
108
+ function getDefaultGrgApiClient() {
109
+ if (!_defaultClient) {
110
+ _defaultClient = new GrgApiClient();
111
+ }
112
+ return _defaultClient;
113
+ }
114
+ function setDefaultGrgApiClient(client) {
115
+ _defaultClient = client;
116
+ }