openttt 0.1.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 (46) hide show
  1. package/README.md +391 -0
  2. package/dist/adaptive_switch.d.ts +44 -0
  3. package/dist/adaptive_switch.js +108 -0
  4. package/dist/auto_mint.d.ts +45 -0
  5. package/dist/auto_mint.js +244 -0
  6. package/dist/dynamic_fee.d.ts +64 -0
  7. package/dist/dynamic_fee.js +203 -0
  8. package/dist/errors.d.ts +45 -0
  9. package/dist/errors.js +74 -0
  10. package/dist/evm_connector.d.ts +88 -0
  11. package/dist/evm_connector.js +297 -0
  12. package/dist/golay.d.ts +6 -0
  13. package/dist/golay.js +166 -0
  14. package/dist/grg_forward.d.ts +6 -0
  15. package/dist/grg_forward.js +59 -0
  16. package/dist/grg_inverse.d.ts +7 -0
  17. package/dist/grg_inverse.js +97 -0
  18. package/dist/grg_pipeline.d.ts +13 -0
  19. package/dist/grg_pipeline.js +64 -0
  20. package/dist/index.d.ts +21 -0
  21. package/dist/index.js +38 -0
  22. package/dist/logger.d.ts +18 -0
  23. package/dist/logger.js +51 -0
  24. package/dist/networks.d.ts +13 -0
  25. package/dist/networks.js +23 -0
  26. package/dist/pool_registry.d.ts +58 -0
  27. package/dist/pool_registry.js +129 -0
  28. package/dist/protocol_fee.d.ts +56 -0
  29. package/dist/protocol_fee.js +176 -0
  30. package/dist/reed_solomon.d.ts +12 -0
  31. package/dist/reed_solomon.js +179 -0
  32. package/dist/signer.d.ts +76 -0
  33. package/dist/signer.js +329 -0
  34. package/dist/time_synthesis.d.ts +49 -0
  35. package/dist/time_synthesis.js +372 -0
  36. package/dist/ttt_builder.d.ts +32 -0
  37. package/dist/ttt_builder.js +84 -0
  38. package/dist/ttt_client.d.ts +118 -0
  39. package/dist/ttt_client.js +352 -0
  40. package/dist/types.d.ts +141 -0
  41. package/dist/types.js +9 -0
  42. package/dist/v4_hook.d.ts +43 -0
  43. package/dist/v4_hook.js +115 -0
  44. package/dist/x402_enforcer.d.ts +29 -0
  45. package/dist/x402_enforcer.js +67 -0
  46. package/package.json +51 -0
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ProtocolFeeCollector = void 0;
4
+ const ethers_1 = require("ethers");
5
+ const logger_1 = require("./logger");
6
+ /**
7
+ * ProtocolFeeCollector - Helm 프로토콜 수수료 수취 및 검증 담당
8
+ * x402 컴플라이언스를 위해 EIP-712 서명 검증을 포함
9
+ */
10
+ class ProtocolFeeCollector {
11
+ totalCollected = 0n;
12
+ chainId;
13
+ verifyingContract;
14
+ // P1-2 FIX: Bounded LRU replay cache (max 10K entries, 1h TTL) instead of unbounded Set
15
+ usedSignatures = new Map();
16
+ MAX_REPLAY_CACHE = 10000;
17
+ REPLAY_TTL_MS = 3600000; // 1 hour
18
+ evmConnector;
19
+ protocolFeeRecipient;
20
+ feeContract = null;
21
+ constructor(chainId, verifyingContract, evmConnector, protocolFeeRecipient) {
22
+ // R3-P0-2: Validate chainId is a positive integer to prevent cross-chain replay
23
+ if (!Number.isInteger(chainId) || chainId <= 0) {
24
+ throw new Error(`[ProtocolFee] Invalid chainId: ${chainId}. Must be a positive integer.`);
25
+ }
26
+ this.chainId = chainId;
27
+ this.verifyingContract = ethers_1.ethers.getAddress(verifyingContract);
28
+ this.evmConnector = evmConnector;
29
+ this.protocolFeeRecipient = ethers_1.ethers.getAddress(protocolFeeRecipient);
30
+ }
31
+ /**
32
+ * R3-P0-2: Verify chainId matches the actual connected network.
33
+ * Must be called after EVMConnector.connect() to prevent cross-chain signature replay.
34
+ */
35
+ async validateChainId() {
36
+ const provider = this.evmConnector.getProvider();
37
+ const network = await provider.getNetwork();
38
+ if (Number(network.chainId) !== this.chainId) {
39
+ throw new Error(`[ProtocolFee] Chain ID mismatch: configured ${this.chainId}, network reports ${network.chainId}. Cross-chain replay risk!`);
40
+ }
41
+ }
42
+ getFeeContract() {
43
+ if (this.feeContract)
44
+ return this.feeContract;
45
+ const abi = [
46
+ "function collectFee(address token, uint256 amount, bytes calldata signature, uint256 nonce, uint256 deadline) external"
47
+ ];
48
+ // ProtocolFeeCollector uses verifyingContract as the ProtocolFee.sol address
49
+ this.feeContract = new ethers_1.ethers.Contract(this.verifyingContract, abi, this.evmConnector.getSigner());
50
+ return this.feeContract;
51
+ }
52
+ /**
53
+ * 민팅 수수료 수취 (Stablecoin)
54
+ * @param feeCalc - DynamicFeeEngine에서 계산된 수수료 정보
55
+ * @param signature - EIP-712 서명 (필수, x402 검증용)
56
+ * @param user - 서명자 주소
57
+ * @param nonce - 중복 방지 nonce
58
+ * @param deadline - 서명 유효 기한
59
+ */
60
+ async collectMintFee(feeCalc, signature, user, nonce, deadline) {
61
+ try {
62
+ await this.verifySignature(feeCalc, signature, user, nonce, deadline);
63
+ // Actual on-chain collection
64
+ const contract = this.getFeeContract();
65
+ const tx = await contract.collectFee(ethers_1.ethers.getAddress(feeCalc.feeTokenAddress), feeCalc.protocolFeeUsd, signature, nonce, deadline);
66
+ await tx.wait();
67
+ this.totalCollected += feeCalc.protocolFeeUsd;
68
+ logger_1.logger.info(`[ProtocolFee] Mint fee collected on-chain: ${feeCalc.protocolFeeUsd} ${feeCalc.feeToken}. TX: ${tx.hash}`);
69
+ }
70
+ catch (error) {
71
+ throw new Error(`[ProtocolFee] Mint fee collection failed: ${(error instanceof Error ? error.message : String(error))}`);
72
+ }
73
+ }
74
+ /**
75
+ * 소각 수수료 수취
76
+ * @param feeCalc - DynamicFeeEngine에서 계산된 수수료 정보
77
+ * @param signature - EIP-712 서명 (필수)
78
+ * @param user - 서명자 주소
79
+ * @param nonce - 중복 방지 nonce
80
+ * @param deadline - 서명 유효 기한
81
+ */
82
+ async collectBurnFee(feeCalc, signature, user, nonce, deadline) {
83
+ try {
84
+ await this.verifySignature(feeCalc, signature, user, nonce, deadline);
85
+ // Actual on-chain collection
86
+ const contract = this.getFeeContract();
87
+ const tx = await contract.collectFee(ethers_1.ethers.getAddress(feeCalc.feeTokenAddress), feeCalc.protocolFeeUsd, signature, nonce, deadline);
88
+ await tx.wait();
89
+ this.totalCollected += feeCalc.protocolFeeUsd;
90
+ logger_1.logger.info(`[ProtocolFee] Burn fee collected on-chain: ${feeCalc.protocolFeeUsd} ${feeCalc.feeToken}. TX: ${tx.hash}`);
91
+ }
92
+ catch (error) {
93
+ throw new Error(`[ProtocolFee] Burn fee collection failed: ${(error instanceof Error ? error.message : String(error))}`);
94
+ }
95
+ }
96
+ /**
97
+ * 현재까지 수취한 총 수수료 반환
98
+ */
99
+ async getCollectedFees() {
100
+ return this.totalCollected;
101
+ }
102
+ /**
103
+ * P1-2: Prune expired signatures from replay cache
104
+ */
105
+ lastPruneTime = 0;
106
+ static PRUNE_INTERVAL_MS = 60000; // R3-P1-5: Prune at most once per minute
107
+ pruneExpiredSignatures() {
108
+ const now = Date.now();
109
+ // R3-P1-5: Only prune periodically, not on every call — prevents O(n) DoS
110
+ if (now - this.lastPruneTime < ProtocolFeeCollector.PRUNE_INTERVAL_MS &&
111
+ this.usedSignatures.size <= this.MAX_REPLAY_CACHE) {
112
+ return;
113
+ }
114
+ this.lastPruneTime = now;
115
+ for (const [sig, ts] of this.usedSignatures) {
116
+ if (now - ts > this.REPLAY_TTL_MS) {
117
+ this.usedSignatures.delete(sig);
118
+ }
119
+ }
120
+ // If still over limit, remove oldest entries
121
+ if (this.usedSignatures.size > this.MAX_REPLAY_CACHE) {
122
+ const entries = [...this.usedSignatures.entries()].sort((a, b) => a[1] - b[1]);
123
+ const toRemove = entries.slice(0, entries.length - this.MAX_REPLAY_CACHE);
124
+ for (const [sig] of toRemove) {
125
+ this.usedSignatures.delete(sig);
126
+ }
127
+ }
128
+ }
129
+ /**
130
+ * EIP-712 서명 검증 (x402 compliance)
131
+ */
132
+ async verifySignature(feeCalc, signature, user, nonce, deadline) {
133
+ // B1-2 + P1-2: Bounded replay protection with TTL
134
+ this.pruneExpiredSignatures();
135
+ if (this.usedSignatures.has(signature)) {
136
+ throw new Error("Signature already used (replay protection)");
137
+ }
138
+ // B1-2: Deadline check
139
+ const now = Math.floor(Date.now() / 1000);
140
+ if (deadline < now) {
141
+ throw new Error("Signature deadline expired");
142
+ }
143
+ const normalizedUser = ethers_1.ethers.getAddress(user);
144
+ const domain = {
145
+ name: "Helm Protocol",
146
+ version: "1",
147
+ chainId: this.chainId,
148
+ verifyingContract: this.verifyingContract
149
+ };
150
+ const types = {
151
+ CollectFee: [
152
+ { name: "token", type: "address" },
153
+ { name: "amount", type: "uint256" },
154
+ { name: "nonce", type: "uint256" },
155
+ { name: "deadline", type: "uint256" }
156
+ ]
157
+ };
158
+ const value = {
159
+ token: ethers_1.ethers.getAddress(feeCalc.feeTokenAddress),
160
+ amount: feeCalc.protocolFeeUsd,
161
+ nonce: nonce,
162
+ deadline: deadline
163
+ };
164
+ try {
165
+ const recoveredAddress = ethers_1.ethers.verifyTypedData(domain, types, value, signature);
166
+ if (ethers_1.ethers.getAddress(recoveredAddress) !== normalizedUser) {
167
+ throw new Error("Invalid EIP-712 signature: signer mismatch");
168
+ }
169
+ this.usedSignatures.set(signature, Date.now()); // Mark as used with timestamp
170
+ }
171
+ catch (error) {
172
+ throw new Error(`[ProtocolFee] Signature verification failed: ${(error instanceof Error ? error.message : String(error))}`);
173
+ }
174
+ }
175
+ }
176
+ exports.ProtocolFeeCollector = ProtocolFeeCollector;
@@ -0,0 +1,12 @@
1
+ export declare class ReedSolomon {
2
+ private static expTable;
3
+ private static logTable;
4
+ private static initialized;
5
+ static init(): void;
6
+ static mul(a: number, b: number): number;
7
+ static div(a: number, b: number): number;
8
+ private static invertMatrix;
9
+ private static buildVandermonde;
10
+ static encode(data: Uint8Array, dataShards?: number, parityShards?: number): Uint8Array[];
11
+ static decode(shards: (Uint8Array | null)[], dataShards?: number, parityShards?: number): Uint8Array;
12
+ }
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ReedSolomon = void 0;
4
+ class ReedSolomon {
5
+ static expTable = new Uint8Array(256);
6
+ static logTable = new Uint8Array(256);
7
+ static initialized = false;
8
+ static init() {
9
+ if (this.initialized)
10
+ return;
11
+ let x = 1;
12
+ for (let i = 0; i < 255; i++) {
13
+ this.expTable[i] = x;
14
+ this.logTable[x] = i;
15
+ x <<= 1;
16
+ if (x & 0x100) {
17
+ x ^= 0x11D; // x^8 + x^4 + x^3 + x^2 + 1
18
+ }
19
+ }
20
+ this.expTable[255] = this.expTable[0];
21
+ this.logTable[0] = 0;
22
+ this.initialized = true;
23
+ }
24
+ static mul(a, b) {
25
+ if (a === 0 || b === 0)
26
+ return 0;
27
+ return this.expTable[(this.logTable[a] + this.logTable[b]) % 255];
28
+ }
29
+ static div(a, b) {
30
+ if (b === 0)
31
+ throw new Error("Division by zero");
32
+ if (a === 0)
33
+ return 0;
34
+ return this.expTable[(this.logTable[a] - this.logTable[b] + 255) % 255];
35
+ }
36
+ static invertMatrix(matrix) {
37
+ const n = matrix.length;
38
+ const aug = [];
39
+ for (let i = 0; i < n; i++) {
40
+ aug[i] = [];
41
+ for (let j = 0; j < n; j++) {
42
+ aug[i][j] = matrix[i][j];
43
+ }
44
+ for (let j = 0; j < n; j++) {
45
+ aug[i][j + n] = (i === j) ? 1 : 0;
46
+ }
47
+ }
48
+ for (let i = 0; i < n; i++) {
49
+ let pivot = i;
50
+ while (pivot < n && aug[pivot][i] === 0) {
51
+ pivot++;
52
+ }
53
+ if (pivot === n)
54
+ throw new Error("Singular matrix");
55
+ if (pivot !== i) {
56
+ const temp = aug[i];
57
+ aug[i] = aug[pivot];
58
+ aug[pivot] = temp;
59
+ }
60
+ const pivotVal = aug[i][i];
61
+ if (pivotVal !== 1) {
62
+ for (let j = i; j < 2 * n; j++) {
63
+ aug[i][j] = this.div(aug[i][j], pivotVal);
64
+ }
65
+ }
66
+ for (let j = 0; j < n; j++) {
67
+ if (i !== j && aug[j][i] !== 0) {
68
+ const factor = aug[j][i];
69
+ for (let k = i; k < 2 * n; k++) {
70
+ aug[j][k] ^= this.mul(factor, aug[i][k]);
71
+ }
72
+ }
73
+ }
74
+ }
75
+ const inv = [];
76
+ for (let i = 0; i < n; i++) {
77
+ inv[i] = [];
78
+ for (let j = 0; j < n; j++) {
79
+ inv[i][j] = aug[i][j + n];
80
+ }
81
+ }
82
+ return inv;
83
+ }
84
+ static buildVandermonde(rows, cols) {
85
+ const V = [];
86
+ for (let r = 0; r < rows; r++) {
87
+ V[r] = [];
88
+ const x = r + 1;
89
+ for (let c = 0; c < cols; c++) {
90
+ if (c === 0) {
91
+ V[r][c] = 1;
92
+ }
93
+ else {
94
+ V[r][c] = this.mul(V[r][c - 1], x);
95
+ }
96
+ }
97
+ }
98
+ const V_top = [];
99
+ for (let i = 0; i < cols; i++) {
100
+ V_top.push([...V[i]]);
101
+ }
102
+ const V_top_inv = this.invertMatrix(V_top);
103
+ const G = [];
104
+ for (let r = 0; r < rows; r++) {
105
+ G[r] = [];
106
+ for (let c = 0; c < cols; c++) {
107
+ let val = 0;
108
+ for (let k = 0; k < cols; k++) {
109
+ val ^= this.mul(V[r][k], V_top_inv[k][c]);
110
+ }
111
+ G[r][c] = val;
112
+ }
113
+ }
114
+ return G;
115
+ }
116
+ static encode(data, dataShards = 4, parityShards = 2) {
117
+ this.init();
118
+ const totalShards = dataShards + parityShards;
119
+ const rawShardSize = Math.ceil(data.length / dataShards);
120
+ const shardSize = Math.ceil(rawShardSize / 3) * 3;
121
+ const matrix = this.buildVandermonde(totalShards, dataShards);
122
+ const shards = [];
123
+ for (let i = 0; i < totalShards; i++) {
124
+ shards.push(new Uint8Array(shardSize));
125
+ }
126
+ for (let i = 0; i < dataShards; i++) {
127
+ shards[i].set(data.subarray(i * shardSize, Math.min((i + 1) * shardSize, data.length)));
128
+ }
129
+ for (let c = 0; c < shardSize; c++) {
130
+ for (let r = dataShards; r < totalShards; r++) {
131
+ let val = 0;
132
+ for (let j = 0; j < dataShards; j++) {
133
+ val ^= this.mul(matrix[r][j], shards[j][c]);
134
+ }
135
+ shards[r][c] = val;
136
+ }
137
+ }
138
+ return shards;
139
+ }
140
+ static decode(shards, dataShards = 4, parityShards = 2) {
141
+ this.init();
142
+ const totalShards = dataShards + parityShards;
143
+ if (shards.length !== totalShards) {
144
+ throw new Error(`[RS] Expected ${totalShards} shards, got ${shards.length}`);
145
+ }
146
+ const presentIndices = [];
147
+ const presentShards = [];
148
+ for (let i = 0; i < totalShards; i++) {
149
+ if (shards[i] !== null && shards[i] !== undefined) {
150
+ presentIndices.push(i);
151
+ presentShards.push(shards[i]);
152
+ if (presentIndices.length === dataShards)
153
+ break;
154
+ }
155
+ }
156
+ if (presentIndices.length < dataShards) {
157
+ throw new Error(`[RS] Not enough shards for recovery: need ${dataShards}, got ${presentIndices.length}`);
158
+ }
159
+ const shardSize = presentShards[0].length;
160
+ const origMatrix = this.buildVandermonde(totalShards, dataShards);
161
+ const subMatrix = [];
162
+ for (let i = 0; i < dataShards; i++) {
163
+ subMatrix.push([...origMatrix[presentIndices[i]]]);
164
+ }
165
+ const invMatrix = this.invertMatrix(subMatrix);
166
+ const result = new Uint8Array(shardSize * dataShards);
167
+ for (let c = 0; c < shardSize; c++) {
168
+ for (let r = 0; r < dataShards; r++) {
169
+ let val = 0;
170
+ for (let j = 0; j < dataShards; j++) {
171
+ val ^= this.mul(invMatrix[r][j], presentShards[j][c]);
172
+ }
173
+ result[r * shardSize + c] = val;
174
+ }
175
+ }
176
+ return result;
177
+ }
178
+ }
179
+ exports.ReedSolomon = ReedSolomon;
@@ -0,0 +1,76 @@
1
+ import { Signer, Wallet } from "ethers";
2
+ import { TurnkeySigner } from "@turnkey/ethers";
3
+ /**
4
+ * Supported signer types in TTT SDK
5
+ */
6
+ export declare enum SignerType {
7
+ PrivateKey = "privateKey",
8
+ Turnkey = "turnkey",
9
+ Privy = "privy",
10
+ KMS = "kms"
11
+ }
12
+ /**
13
+ * Discriminated union for signer configuration
14
+ */
15
+ export type SignerConfig = {
16
+ type: 'privateKey';
17
+ key?: string;
18
+ envVar?: string;
19
+ } | {
20
+ type: 'turnkey';
21
+ apiBaseUrl: string;
22
+ organizationId: string;
23
+ privateKeyId: string;
24
+ apiPublicKey: string;
25
+ apiPrivateKey: string;
26
+ } | {
27
+ type: 'privy';
28
+ appId: string;
29
+ appSecret: string;
30
+ walletId?: string;
31
+ } | {
32
+ type: 'kms';
33
+ provider: 'aws' | 'gcp';
34
+ keyId: string;
35
+ region?: string;
36
+ projectId?: string;
37
+ locationId?: string;
38
+ keyRingId?: string;
39
+ keyVersionId?: string;
40
+ };
41
+ /**
42
+ * Base wrapper for all signers to ensure unified interface within the SDK
43
+ */
44
+ export declare abstract class TTTAbstractSigner {
45
+ readonly inner: Signer;
46
+ constructor(inner: Signer);
47
+ getAddress(): Promise<string>;
48
+ }
49
+ /**
50
+ * Standard Private Key Signer (Institutional/Dev use)
51
+ */
52
+ export declare class PrivateKeySigner extends TTTAbstractSigner {
53
+ constructor(signer: Wallet);
54
+ }
55
+ /**
56
+ * TEE-based institution-grade signer (Turnkey)
57
+ */
58
+ export declare class TurnkeySignerWrapper extends TTTAbstractSigner {
59
+ constructor(signer: TurnkeySigner);
60
+ }
61
+ /**
62
+ * Social/Embedded wallet signer (Privy)
63
+ */
64
+ export declare class PrivySigner extends TTTAbstractSigner {
65
+ constructor(signer: Signer);
66
+ }
67
+ /**
68
+ * Cloud HSM (KMS) based signer
69
+ */
70
+ export declare class KMSSigner extends TTTAbstractSigner {
71
+ constructor(signer: Signer);
72
+ }
73
+ /**
74
+ * Factory function to create appropriate signer based on config
75
+ */
76
+ export declare function createSigner(config: SignerConfig): Promise<TTTAbstractSigner>;