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.
- package/README.md +52 -30
- package/dist/adaptive_switch.d.ts +22 -7
- package/dist/adaptive_switch.js +52 -15
- package/dist/auto_mint.d.ts +22 -7
- package/dist/auto_mint.js +107 -30
- package/dist/ct_log.d.ts +47 -0
- package/dist/ct_log.js +107 -0
- package/dist/dynamic_fee.d.ts +13 -2
- package/dist/dynamic_fee.js +62 -11
- package/dist/errors.d.ts +44 -25
- package/dist/errors.js +58 -42
- package/dist/evm_connector.d.ts +28 -1
- package/dist/evm_connector.js +124 -32
- package/dist/grg_api_client.d.ts +41 -0
- package/dist/grg_api_client.js +116 -0
- package/dist/http_client.d.ts +98 -0
- package/dist/http_client.js +252 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +5 -5
- package/dist/logger.d.ts +36 -4
- package/dist/logger.js +70 -11
- package/dist/networks.d.ts +21 -0
- package/dist/networks.js +30 -4
- package/dist/pool_registry.d.ts +9 -0
- package/dist/pool_registry.js +37 -0
- package/dist/pot_signer.d.ts +15 -0
- package/dist/pot_signer.js +28 -0
- package/dist/protocol_fee.d.ts +42 -26
- package/dist/protocol_fee.js +77 -54
- package/dist/revenue_tiers.d.ts +36 -0
- package/dist/revenue_tiers.js +83 -0
- package/dist/signer.d.ts +1 -2
- package/dist/signer.js +72 -14
- package/dist/time_synthesis.d.ts +38 -0
- package/dist/time_synthesis.js +131 -21
- package/dist/trust_store.d.ts +49 -0
- package/dist/trust_store.js +89 -0
- package/dist/ttt_builder.d.ts +1 -1
- package/dist/ttt_builder.js +2 -2
- package/dist/ttt_client.d.ts +42 -29
- package/dist/ttt_client.js +117 -28
- package/dist/types.d.ts +46 -3
- package/dist/v4_hook.d.ts +10 -2
- package/dist/v4_hook.js +10 -2
- package/dist/x402_enforcer.d.ts +17 -2
- package/dist/x402_enforcer.js +27 -2
- package/package.json +6 -2
- package/dist/golay.d.ts +0 -6
- package/dist/golay.js +0 -166
- package/dist/grg_forward.d.ts +0 -11
- package/dist/grg_forward.js +0 -74
- package/dist/grg_inverse.d.ts +0 -7
- package/dist/grg_inverse.js +0 -100
- package/dist/grg_pipeline.d.ts +0 -13
- package/dist/grg_pipeline.js +0 -64
- package/dist/reed_solomon.d.ts +0 -12
- package/dist/reed_solomon.js +0 -179
- package/vendor/helm-crypto/golay.d.ts +0 -6
- package/vendor/helm-crypto/golay.js +0 -167
- package/vendor/helm-crypto/golay.js.map +0 -1
- package/vendor/helm-crypto/grg_forward.d.ts +0 -22
- package/vendor/helm-crypto/grg_forward.js +0 -89
- package/vendor/helm-crypto/grg_forward.js.map +0 -1
- package/vendor/helm-crypto/grg_inverse.d.ts +0 -16
- package/vendor/helm-crypto/grg_inverse.js +0 -118
- package/vendor/helm-crypto/grg_inverse.js.map +0 -1
- package/vendor/helm-crypto/grg_pipeline.d.ts +0 -13
- package/vendor/helm-crypto/grg_pipeline.js +0 -66
- package/vendor/helm-crypto/grg_pipeline.js.map +0 -1
- package/vendor/helm-crypto/index.d.ts +0 -5
- package/vendor/helm-crypto/index.js +0 -17
- package/vendor/helm-crypto/index.js.map +0 -1
- package/vendor/helm-crypto/logger.d.ts +0 -6
- package/vendor/helm-crypto/logger.js +0 -11
- package/vendor/helm-crypto/logger.js.map +0 -1
- package/vendor/helm-crypto/reed_solomon.d.ts +0 -37
- package/vendor/helm-crypto/reed_solomon.js +0 -210
- package/vendor/helm-crypto/reed_solomon.js.map +0 -1
package/dist/pool_registry.js
CHANGED
|
@@ -125,5 +125,42 @@ class PoolRegistry {
|
|
|
125
125
|
listPools() {
|
|
126
126
|
return Array.from(this.pools.keys());
|
|
127
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Serialize registry state to JSON for persistence across restarts.
|
|
130
|
+
* Allows operators to restore pool registrations and stats without re-registering.
|
|
131
|
+
*/
|
|
132
|
+
serialize() {
|
|
133
|
+
const poolsArray = Array.from(this.pools.entries()).map(([address, stats]) => ({
|
|
134
|
+
address,
|
|
135
|
+
chainId: stats.chainId,
|
|
136
|
+
minted: stats.minted.toString(),
|
|
137
|
+
burned: stats.burned.toString(),
|
|
138
|
+
}));
|
|
139
|
+
const tokenMappings = Array.from(this.tokenToPool.entries()).map(([tokenId, poolAddr]) => ({
|
|
140
|
+
tokenId,
|
|
141
|
+
poolAddress: poolAddr,
|
|
142
|
+
}));
|
|
143
|
+
return JSON.stringify({ pools: poolsArray, tokenMappings });
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Reconstruct a PoolRegistry from previously serialized JSON state.
|
|
147
|
+
*/
|
|
148
|
+
static deserialize(json) {
|
|
149
|
+
const data = JSON.parse(json);
|
|
150
|
+
const instance = new PoolRegistry();
|
|
151
|
+
for (const p of data.pools) {
|
|
152
|
+
instance.pools.set(p.address, {
|
|
153
|
+
chainId: p.chainId,
|
|
154
|
+
minted: BigInt(p.minted),
|
|
155
|
+
burned: BigInt(p.burned),
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
if (data.tokenMappings) {
|
|
159
|
+
for (const t of data.tokenMappings) {
|
|
160
|
+
instance.tokenToPool.set(t.tokenId, t.poolAddress);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return instance;
|
|
164
|
+
}
|
|
128
165
|
}
|
|
129
166
|
exports.PoolRegistry = PoolRegistry;
|
package/dist/pot_signer.d.ts
CHANGED
|
@@ -25,5 +25,20 @@ export declare class PotSigner {
|
|
|
25
25
|
* @param expectedPubKey - optional: reject if issuerPubKey doesn't match
|
|
26
26
|
* @returns true if signature is valid
|
|
27
27
|
*/
|
|
28
|
+
/**
|
|
29
|
+
* Load a PotSigner from a PKCS8 DER hex file.
|
|
30
|
+
* @param path - path to file containing hex-encoded PKCS8 DER private key
|
|
31
|
+
*/
|
|
32
|
+
static fromFile(path: string): PotSigner;
|
|
33
|
+
/**
|
|
34
|
+
* Load a PotSigner from file if it exists, otherwise generate a new one and save it.
|
|
35
|
+
* @param path - path to file for persistent key storage
|
|
36
|
+
*/
|
|
37
|
+
static createOrLoad(path: string): PotSigner;
|
|
38
|
+
/**
|
|
39
|
+
* Save the private key (PKCS8 DER hex) to a file with mode 0o600.
|
|
40
|
+
* @param path - destination file path
|
|
41
|
+
*/
|
|
42
|
+
saveToFile(path: string): void;
|
|
28
43
|
static verifyPotSignature(potHash: string, potSig: PotSignature, expectedPubKey?: string): boolean;
|
|
29
44
|
}
|
package/dist/pot_signer.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.PotSigner = void 0;
|
|
|
4
4
|
// sdk/src/pot_signer.ts — Ed25519 signing for Proof of Time (Non-repudiation)
|
|
5
5
|
// Uses Node.js built-in crypto.sign/verify with Ed25519
|
|
6
6
|
const crypto_1 = require("crypto");
|
|
7
|
+
const fs_1 = require("fs");
|
|
7
8
|
class PotSigner {
|
|
8
9
|
privateKey;
|
|
9
10
|
publicKey;
|
|
@@ -52,6 +53,33 @@ class PotSigner {
|
|
|
52
53
|
* @param expectedPubKey - optional: reject if issuerPubKey doesn't match
|
|
53
54
|
* @returns true if signature is valid
|
|
54
55
|
*/
|
|
56
|
+
/**
|
|
57
|
+
* Load a PotSigner from a PKCS8 DER hex file.
|
|
58
|
+
* @param path - path to file containing hex-encoded PKCS8 DER private key
|
|
59
|
+
*/
|
|
60
|
+
static fromFile(path) {
|
|
61
|
+
const hex = (0, fs_1.readFileSync)(path, 'utf-8').trim();
|
|
62
|
+
return new PotSigner(hex);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Load a PotSigner from file if it exists, otherwise generate a new one and save it.
|
|
66
|
+
* @param path - path to file for persistent key storage
|
|
67
|
+
*/
|
|
68
|
+
static createOrLoad(path) {
|
|
69
|
+
if ((0, fs_1.existsSync)(path)) {
|
|
70
|
+
return PotSigner.fromFile(path);
|
|
71
|
+
}
|
|
72
|
+
const signer = new PotSigner();
|
|
73
|
+
signer.saveToFile(path);
|
|
74
|
+
return signer;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Save the private key (PKCS8 DER hex) to a file with mode 0o600.
|
|
78
|
+
* @param path - destination file path
|
|
79
|
+
*/
|
|
80
|
+
saveToFile(path) {
|
|
81
|
+
(0, fs_1.writeFileSync)(path, this.getPrivateKeyHex(), { mode: 0o600 });
|
|
82
|
+
}
|
|
55
83
|
static verifyPotSignature(potHash, potSig, expectedPubKey) {
|
|
56
84
|
if (expectedPubKey && potSig.issuerPubKey !== expectedPubKey)
|
|
57
85
|
return false;
|
package/dist/protocol_fee.d.ts
CHANGED
|
@@ -1,20 +1,42 @@
|
|
|
1
1
|
import { FeeCalculation } from "./dynamic_fee";
|
|
2
2
|
import { EVMConnector } from "./evm_connector";
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Pluggable replay cache interface for signature deduplication.
|
|
5
|
+
* Implement this to use Redis, database, or other external stores.
|
|
6
|
+
*/
|
|
7
|
+
export interface ReplayCache {
|
|
8
|
+
has(key: string): Promise<boolean>;
|
|
9
|
+
set(key: string, ttlMs: number): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Default in-memory replay cache with bounded size and TTL eviction.
|
|
13
|
+
* Suitable for single-process deployments; use a distributed ReplayCache
|
|
14
|
+
* implementation (e.g., Redis) for multi-node setups.
|
|
15
|
+
*/
|
|
16
|
+
export declare class InMemoryReplayCache implements ReplayCache {
|
|
17
|
+
private entries;
|
|
18
|
+
private readonly maxEntries;
|
|
19
|
+
private readonly defaultTtlMs;
|
|
20
|
+
private lastPruneTime;
|
|
21
|
+
private static readonly PRUNE_INTERVAL_MS;
|
|
22
|
+
constructor(maxEntries?: number, defaultTtlMs?: number);
|
|
23
|
+
has(key: string): Promise<boolean>;
|
|
24
|
+
set(key: string, ttlMs: number): Promise<void>;
|
|
25
|
+
private pruneIfNeeded;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* ProtocolFeeCollector - Handles Helm protocol fee collection and verification.
|
|
29
|
+
* Includes EIP-712 signature verification for x402 compliance.
|
|
6
30
|
*/
|
|
7
31
|
export declare class ProtocolFeeCollector {
|
|
8
32
|
private totalCollected;
|
|
9
33
|
private chainId;
|
|
10
34
|
private verifyingContract;
|
|
11
|
-
private
|
|
12
|
-
private readonly MAX_REPLAY_CACHE;
|
|
13
|
-
private readonly REPLAY_TTL_MS;
|
|
35
|
+
private replayCache;
|
|
14
36
|
private evmConnector;
|
|
15
37
|
private protocolFeeRecipient;
|
|
16
38
|
private feeContract;
|
|
17
|
-
constructor(chainId: number, verifyingContract: string, evmConnector: EVMConnector, protocolFeeRecipient: string);
|
|
39
|
+
constructor(chainId: number, verifyingContract: string, evmConnector: EVMConnector, protocolFeeRecipient: string, replayCache?: ReplayCache);
|
|
18
40
|
/**
|
|
19
41
|
* R3-P0-2: Verify chainId matches the actual connected network.
|
|
20
42
|
* Must be called after EVMConnector.connect() to prevent cross-chain signature replay.
|
|
@@ -22,35 +44,29 @@ export declare class ProtocolFeeCollector {
|
|
|
22
44
|
validateChainId(): Promise<void>;
|
|
23
45
|
private getFeeContract;
|
|
24
46
|
/**
|
|
25
|
-
*
|
|
26
|
-
* @param feeCalc -
|
|
27
|
-
* @param signature - EIP-712
|
|
28
|
-
* @param user -
|
|
29
|
-
* @param nonce -
|
|
30
|
-
* @param deadline -
|
|
47
|
+
* Collect minting fee (Stablecoin).
|
|
48
|
+
* @param feeCalc - Fee calculation result from DynamicFeeEngine.
|
|
49
|
+
* @param signature - EIP-712 signature (required, for x402 verification).
|
|
50
|
+
* @param user - Signer address.
|
|
51
|
+
* @param nonce - Anti-replay nonce.
|
|
52
|
+
* @param deadline - Signature expiration timestamp.
|
|
31
53
|
*/
|
|
32
54
|
collectMintFee(feeCalc: FeeCalculation, signature: string, user: string, nonce: bigint, deadline: number): Promise<void>;
|
|
33
55
|
/**
|
|
34
|
-
*
|
|
35
|
-
* @param feeCalc -
|
|
36
|
-
* @param signature - EIP-712
|
|
37
|
-
* @param user -
|
|
38
|
-
* @param nonce -
|
|
39
|
-
* @param deadline -
|
|
56
|
+
* Collect burn fee.
|
|
57
|
+
* @param feeCalc - Fee calculation result from DynamicFeeEngine.
|
|
58
|
+
* @param signature - EIP-712 signature (required).
|
|
59
|
+
* @param user - Signer address.
|
|
60
|
+
* @param nonce - Anti-replay nonce.
|
|
61
|
+
* @param deadline - Signature expiration timestamp.
|
|
40
62
|
*/
|
|
41
63
|
collectBurnFee(feeCalc: FeeCalculation, signature: string, user: string, nonce: bigint, deadline: number): Promise<void>;
|
|
42
64
|
/**
|
|
43
|
-
*
|
|
65
|
+
* Return total fees collected so far.
|
|
44
66
|
*/
|
|
45
67
|
getCollectedFees(): Promise<bigint>;
|
|
46
68
|
/**
|
|
47
|
-
*
|
|
48
|
-
*/
|
|
49
|
-
private lastPruneTime;
|
|
50
|
-
private static readonly PRUNE_INTERVAL_MS;
|
|
51
|
-
private pruneExpiredSignatures;
|
|
52
|
-
/**
|
|
53
|
-
* EIP-712 서명 검증 (x402 compliance)
|
|
69
|
+
* EIP-712 signature verification (x402 compliance).
|
|
54
70
|
*/
|
|
55
71
|
private verifySignature;
|
|
56
72
|
}
|
package/dist/protocol_fee.js
CHANGED
|
@@ -1,24 +1,74 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ProtocolFeeCollector = void 0;
|
|
3
|
+
exports.ProtocolFeeCollector = exports.InMemoryReplayCache = void 0;
|
|
4
4
|
const ethers_1 = require("ethers");
|
|
5
5
|
const logger_1 = require("./logger");
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Default in-memory replay cache with bounded size and TTL eviction.
|
|
8
|
+
* Suitable for single-process deployments; use a distributed ReplayCache
|
|
9
|
+
* implementation (e.g., Redis) for multi-node setups.
|
|
10
|
+
*/
|
|
11
|
+
class InMemoryReplayCache {
|
|
12
|
+
entries = new Map();
|
|
13
|
+
maxEntries;
|
|
14
|
+
defaultTtlMs;
|
|
15
|
+
lastPruneTime = 0;
|
|
16
|
+
static PRUNE_INTERVAL_MS = 60000;
|
|
17
|
+
constructor(maxEntries = 10000, defaultTtlMs = 3600000) {
|
|
18
|
+
this.maxEntries = maxEntries;
|
|
19
|
+
this.defaultTtlMs = defaultTtlMs;
|
|
20
|
+
}
|
|
21
|
+
async has(key) {
|
|
22
|
+
this.pruneIfNeeded();
|
|
23
|
+
const ts = this.entries.get(key);
|
|
24
|
+
if (ts === undefined)
|
|
25
|
+
return false;
|
|
26
|
+
if (Date.now() - ts > this.defaultTtlMs) {
|
|
27
|
+
this.entries.delete(key);
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
async set(key, ttlMs) {
|
|
33
|
+
this.pruneIfNeeded();
|
|
34
|
+
this.entries.set(key, Date.now());
|
|
35
|
+
}
|
|
36
|
+
pruneIfNeeded() {
|
|
37
|
+
const now = Date.now();
|
|
38
|
+
if (now - this.lastPruneTime < InMemoryReplayCache.PRUNE_INTERVAL_MS &&
|
|
39
|
+
this.entries.size <= this.maxEntries) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
this.lastPruneTime = now;
|
|
43
|
+
for (const [sig, ts] of this.entries) {
|
|
44
|
+
if (now - ts > this.defaultTtlMs) {
|
|
45
|
+
this.entries.delete(sig);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// If still over limit, remove oldest entries
|
|
49
|
+
if (this.entries.size > this.maxEntries) {
|
|
50
|
+
const sorted = [...this.entries.entries()].sort((a, b) => a[1] - b[1]);
|
|
51
|
+
const toRemove = sorted.slice(0, sorted.length - this.maxEntries);
|
|
52
|
+
for (const [sig] of toRemove) {
|
|
53
|
+
this.entries.delete(sig);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.InMemoryReplayCache = InMemoryReplayCache;
|
|
59
|
+
/**
|
|
60
|
+
* ProtocolFeeCollector - Handles Helm protocol fee collection and verification.
|
|
61
|
+
* Includes EIP-712 signature verification for x402 compliance.
|
|
9
62
|
*/
|
|
10
63
|
class ProtocolFeeCollector {
|
|
11
64
|
totalCollected = 0n;
|
|
12
65
|
chainId;
|
|
13
66
|
verifyingContract;
|
|
14
|
-
|
|
15
|
-
usedSignatures = new Map();
|
|
16
|
-
MAX_REPLAY_CACHE = 10000;
|
|
17
|
-
REPLAY_TTL_MS = 3600000; // 1 hour
|
|
67
|
+
replayCache;
|
|
18
68
|
evmConnector;
|
|
19
69
|
protocolFeeRecipient;
|
|
20
70
|
feeContract = null;
|
|
21
|
-
constructor(chainId, verifyingContract, evmConnector, protocolFeeRecipient) {
|
|
71
|
+
constructor(chainId, verifyingContract, evmConnector, protocolFeeRecipient, replayCache) {
|
|
22
72
|
// R3-P0-2: Validate chainId is a positive integer to prevent cross-chain replay
|
|
23
73
|
if (!Number.isInteger(chainId) || chainId <= 0) {
|
|
24
74
|
throw new Error(`[ProtocolFee] Invalid chainId: ${chainId}. Must be a positive integer.`);
|
|
@@ -27,6 +77,7 @@ class ProtocolFeeCollector {
|
|
|
27
77
|
this.verifyingContract = ethers_1.ethers.getAddress(verifyingContract);
|
|
28
78
|
this.evmConnector = evmConnector;
|
|
29
79
|
this.protocolFeeRecipient = ethers_1.ethers.getAddress(protocolFeeRecipient);
|
|
80
|
+
this.replayCache = replayCache ?? new InMemoryReplayCache();
|
|
30
81
|
}
|
|
31
82
|
/**
|
|
32
83
|
* R3-P0-2: Verify chainId matches the actual connected network.
|
|
@@ -50,12 +101,12 @@ class ProtocolFeeCollector {
|
|
|
50
101
|
return this.feeContract;
|
|
51
102
|
}
|
|
52
103
|
/**
|
|
53
|
-
*
|
|
54
|
-
* @param feeCalc -
|
|
55
|
-
* @param signature - EIP-712
|
|
56
|
-
* @param user -
|
|
57
|
-
* @param nonce -
|
|
58
|
-
* @param deadline -
|
|
104
|
+
* Collect minting fee (Stablecoin).
|
|
105
|
+
* @param feeCalc - Fee calculation result from DynamicFeeEngine.
|
|
106
|
+
* @param signature - EIP-712 signature (required, for x402 verification).
|
|
107
|
+
* @param user - Signer address.
|
|
108
|
+
* @param nonce - Anti-replay nonce.
|
|
109
|
+
* @param deadline - Signature expiration timestamp.
|
|
59
110
|
*/
|
|
60
111
|
async collectMintFee(feeCalc, signature, user, nonce, deadline) {
|
|
61
112
|
try {
|
|
@@ -72,12 +123,12 @@ class ProtocolFeeCollector {
|
|
|
72
123
|
}
|
|
73
124
|
}
|
|
74
125
|
/**
|
|
75
|
-
*
|
|
76
|
-
* @param feeCalc -
|
|
77
|
-
* @param signature - EIP-712
|
|
78
|
-
* @param user -
|
|
79
|
-
* @param nonce -
|
|
80
|
-
* @param deadline -
|
|
126
|
+
* Collect burn fee.
|
|
127
|
+
* @param feeCalc - Fee calculation result from DynamicFeeEngine.
|
|
128
|
+
* @param signature - EIP-712 signature (required).
|
|
129
|
+
* @param user - Signer address.
|
|
130
|
+
* @param nonce - Anti-replay nonce.
|
|
131
|
+
* @param deadline - Signature expiration timestamp.
|
|
81
132
|
*/
|
|
82
133
|
async collectBurnFee(feeCalc, signature, user, nonce, deadline) {
|
|
83
134
|
try {
|
|
@@ -94,45 +145,17 @@ class ProtocolFeeCollector {
|
|
|
94
145
|
}
|
|
95
146
|
}
|
|
96
147
|
/**
|
|
97
|
-
*
|
|
148
|
+
* Return total fees collected so far.
|
|
98
149
|
*/
|
|
99
150
|
async getCollectedFees() {
|
|
100
151
|
return this.totalCollected;
|
|
101
152
|
}
|
|
102
153
|
/**
|
|
103
|
-
*
|
|
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)
|
|
154
|
+
* EIP-712 signature verification (x402 compliance).
|
|
131
155
|
*/
|
|
132
156
|
async verifySignature(feeCalc, signature, user, nonce, deadline) {
|
|
133
|
-
// B1-2 + P1-2:
|
|
134
|
-
this.
|
|
135
|
-
if (this.usedSignatures.has(signature)) {
|
|
157
|
+
// B1-2 + P1-2: Replay protection via pluggable cache
|
|
158
|
+
if (await this.replayCache.has(signature)) {
|
|
136
159
|
throw new Error("Signature already used (replay protection)");
|
|
137
160
|
}
|
|
138
161
|
// B1-2: Deadline check
|
|
@@ -142,7 +165,7 @@ class ProtocolFeeCollector {
|
|
|
142
165
|
}
|
|
143
166
|
const normalizedUser = ethers_1.ethers.getAddress(user);
|
|
144
167
|
const domain = {
|
|
145
|
-
name: "
|
|
168
|
+
name: "OpenTTT_ProtocolFee",
|
|
146
169
|
version: "1",
|
|
147
170
|
chainId: this.chainId,
|
|
148
171
|
verifyingContract: this.verifyingContract
|
|
@@ -166,7 +189,7 @@ class ProtocolFeeCollector {
|
|
|
166
189
|
if (ethers_1.ethers.getAddress(recoveredAddress) !== normalizedUser) {
|
|
167
190
|
throw new Error("Invalid EIP-712 signature: signer mismatch");
|
|
168
191
|
}
|
|
169
|
-
this.
|
|
192
|
+
await this.replayCache.set(signature, 3600000); // Mark as used with 1h TTL
|
|
170
193
|
}
|
|
171
194
|
catch (error) {
|
|
172
195
|
throw new Error(`[ProtocolFee] Signature verification failed: ${(error instanceof Error ? error.message : String(error))}`);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Revenue Tier Configuration
|
|
3
|
+
* Reflects the TTT Labs pricing strategy: Free/Sponsor-backed T0 up to Institutional T3.
|
|
4
|
+
*/
|
|
5
|
+
export declare enum RevenueTier {
|
|
6
|
+
T0_EPOCH = "T0_EPOCH",
|
|
7
|
+
T1_BLOCK = "T1_BLOCK",
|
|
8
|
+
T2_SLOT = "T2_SLOT",
|
|
9
|
+
T3_MICRO = "T3_MICRO"
|
|
10
|
+
}
|
|
11
|
+
export interface TierConfig {
|
|
12
|
+
tier: RevenueTier;
|
|
13
|
+
name: string;
|
|
14
|
+
interval: string;
|
|
15
|
+
pricePerTick: number;
|
|
16
|
+
currency: string;
|
|
17
|
+
model: string;
|
|
18
|
+
target: string;
|
|
19
|
+
sponsorEligible: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface SponsorConfig {
|
|
22
|
+
sponsor: string;
|
|
23
|
+
tier: RevenueTier;
|
|
24
|
+
monthlyBudgetUsd: number;
|
|
25
|
+
startDate: string;
|
|
26
|
+
endDate: string;
|
|
27
|
+
}
|
|
28
|
+
export declare const REVENUE_TIERS: Record<RevenueTier, TierConfig>;
|
|
29
|
+
/**
|
|
30
|
+
* Calculate projected monthly cost based on tier and throughput.
|
|
31
|
+
*/
|
|
32
|
+
export declare function calculateMonthlyCost(tier: RevenueTier, ticksPerDay: number): number;
|
|
33
|
+
/**
|
|
34
|
+
* Determine the appropriate tier based on a usage description.
|
|
35
|
+
*/
|
|
36
|
+
export declare function getTierForUseCase(useCase: string): RevenueTier;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Revenue Tier Configuration
|
|
4
|
+
* Reflects the TTT Labs pricing strategy: Free/Sponsor-backed T0 up to Institutional T3.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.REVENUE_TIERS = exports.RevenueTier = void 0;
|
|
8
|
+
exports.calculateMonthlyCost = calculateMonthlyCost;
|
|
9
|
+
exports.getTierForUseCase = getTierForUseCase;
|
|
10
|
+
var RevenueTier;
|
|
11
|
+
(function (RevenueTier) {
|
|
12
|
+
RevenueTier["T0_EPOCH"] = "T0_EPOCH";
|
|
13
|
+
RevenueTier["T1_BLOCK"] = "T1_BLOCK";
|
|
14
|
+
RevenueTier["T2_SLOT"] = "T2_SLOT";
|
|
15
|
+
RevenueTier["T3_MICRO"] = "T3_MICRO";
|
|
16
|
+
})(RevenueTier || (exports.RevenueTier = RevenueTier = {}));
|
|
17
|
+
exports.REVENUE_TIERS = {
|
|
18
|
+
[RevenueTier.T0_EPOCH]: {
|
|
19
|
+
tier: RevenueTier.T0_EPOCH,
|
|
20
|
+
name: "Standard Epoch",
|
|
21
|
+
interval: "6.4 min",
|
|
22
|
+
pricePerTick: 0,
|
|
23
|
+
currency: "USDC",
|
|
24
|
+
model: "sponsor", // Let's Encrypt model: free to user, sponsor-backed
|
|
25
|
+
target: "Standard L1 Swaps / LP Integration",
|
|
26
|
+
sponsorEligible: true
|
|
27
|
+
},
|
|
28
|
+
[RevenueTier.T1_BLOCK]: {
|
|
29
|
+
tier: RevenueTier.T1_BLOCK,
|
|
30
|
+
name: "Fast Block",
|
|
31
|
+
interval: "2 sec",
|
|
32
|
+
pricePerTick: 0.01,
|
|
33
|
+
currency: "USDC",
|
|
34
|
+
model: "sdk_license",
|
|
35
|
+
target: "L2 Sequencer / Standard DeFi",
|
|
36
|
+
sponsorEligible: false
|
|
37
|
+
},
|
|
38
|
+
[RevenueTier.T2_SLOT]: {
|
|
39
|
+
tier: RevenueTier.T2_SLOT,
|
|
40
|
+
name: "High-Frequency Slot",
|
|
41
|
+
interval: "12 sec",
|
|
42
|
+
pricePerTick: 0.05,
|
|
43
|
+
currency: "USDC",
|
|
44
|
+
model: "sdk_license",
|
|
45
|
+
target: "Active Traders / Arbitrage",
|
|
46
|
+
sponsorEligible: false
|
|
47
|
+
},
|
|
48
|
+
[RevenueTier.T3_MICRO]: {
|
|
49
|
+
tier: RevenueTier.T3_MICRO,
|
|
50
|
+
name: "Institutional Micro-Tick",
|
|
51
|
+
interval: "100 ms",
|
|
52
|
+
pricePerTick: 0.10,
|
|
53
|
+
currency: "USDC",
|
|
54
|
+
model: "enterprise",
|
|
55
|
+
target: "Institutional / HFT Pipelines",
|
|
56
|
+
sponsorEligible: false
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Calculate projected monthly cost based on tier and throughput.
|
|
61
|
+
*/
|
|
62
|
+
function calculateMonthlyCost(tier, ticksPerDay) {
|
|
63
|
+
const config = exports.REVENUE_TIERS[tier];
|
|
64
|
+
if (config.pricePerTick === 0)
|
|
65
|
+
return 0;
|
|
66
|
+
return config.pricePerTick * ticksPerDay * 30;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Determine the appropriate tier based on a usage description.
|
|
70
|
+
*/
|
|
71
|
+
function getTierForUseCase(useCase) {
|
|
72
|
+
const lowerCase = useCase.toLowerCase();
|
|
73
|
+
if (lowerCase.includes("institutional") || lowerCase.includes("hft") || lowerCase.includes("micro")) {
|
|
74
|
+
return RevenueTier.T3_MICRO;
|
|
75
|
+
}
|
|
76
|
+
if (lowerCase.includes("arbitrage") || lowerCase.includes("trader") || lowerCase.includes("slot")) {
|
|
77
|
+
return RevenueTier.T2_SLOT;
|
|
78
|
+
}
|
|
79
|
+
if (lowerCase.includes("l2") || lowerCase.includes("block") || lowerCase.includes("sequencer")) {
|
|
80
|
+
return RevenueTier.T1_BLOCK;
|
|
81
|
+
}
|
|
82
|
+
return RevenueTier.T0_EPOCH;
|
|
83
|
+
}
|
package/dist/signer.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Signer, Wallet } from "ethers";
|
|
2
|
-
import { TurnkeySigner } from "@turnkey/ethers";
|
|
3
2
|
/**
|
|
4
3
|
* Supported signer types in TTT SDK
|
|
5
4
|
*/
|
|
@@ -56,7 +55,7 @@ export declare class PrivateKeySigner extends TTTAbstractSigner {
|
|
|
56
55
|
* TEE-based institution-grade signer (Turnkey)
|
|
57
56
|
*/
|
|
58
57
|
export declare class TurnkeySignerWrapper extends TTTAbstractSigner {
|
|
59
|
-
constructor(signer:
|
|
58
|
+
constructor(signer: Signer);
|
|
60
59
|
}
|
|
61
60
|
/**
|
|
62
61
|
* Social/Embedded wallet signer (Privy)
|