@gvnrdao/dh-sdk 0.0.293 → 0.0.295
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/browser/dist/833.browser.js +2 -0
- package/browser/dist/833.browser.js.LICENSE.txt +1 -0
- package/browser/dist/browser.js +1 -1
- package/dist/index.js +505 -173
- package/dist/index.mjs +505 -173
- package/dist/modules/bitcoin/bitcoin-operations.module.d.ts +2 -10
- package/dist/modules/cache/cache-manager.module.d.ts +208 -41
- package/dist/modules/diamond-hands-sdk.d.ts +20 -5
- package/dist/modules/loan/loan-query.module.d.ts +1 -5
- package/dist/modules/pkp/pkp-manager.module.d.ts +1 -5
- package/dist/utils/quantum-timing.d.ts +68 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -3744,7 +3744,7 @@ var require_abstract_coder = __commonJS({
|
|
|
3744
3744
|
function toObject2(names2, items, deep) {
|
|
3745
3745
|
if (names2.indexOf(null) >= 0) {
|
|
3746
3746
|
return items.map((item, index) => {
|
|
3747
|
-
if (item instanceof
|
|
3747
|
+
if (item instanceof Result11) {
|
|
3748
3748
|
return toObject2(getNames2(item), item, deep);
|
|
3749
3749
|
}
|
|
3750
3750
|
return item;
|
|
@@ -3753,7 +3753,7 @@ var require_abstract_coder = __commonJS({
|
|
|
3753
3753
|
return names2.reduce((accum, name, index) => {
|
|
3754
3754
|
let item = items.getValue(name);
|
|
3755
3755
|
if (!(name in accum)) {
|
|
3756
|
-
if (deep && item instanceof
|
|
3756
|
+
if (deep && item instanceof Result11) {
|
|
3757
3757
|
item = toObject2(getNames2(item), item, deep);
|
|
3758
3758
|
}
|
|
3759
3759
|
accum[name] = item;
|
|
@@ -3761,7 +3761,7 @@ var require_abstract_coder = __commonJS({
|
|
|
3761
3761
|
return accum;
|
|
3762
3762
|
}, {});
|
|
3763
3763
|
}
|
|
3764
|
-
var
|
|
3764
|
+
var Result11 = class _Result extends Array {
|
|
3765
3765
|
// No longer used; but cannot be removed as it will remove the
|
|
3766
3766
|
// #private field from the .d.ts which may break backwards
|
|
3767
3767
|
// compatibility
|
|
@@ -3965,7 +3965,7 @@ var require_abstract_coder = __commonJS({
|
|
|
3965
3965
|
return new _Result(_guard5, items, keys);
|
|
3966
3966
|
}
|
|
3967
3967
|
};
|
|
3968
|
-
exports2.Result =
|
|
3968
|
+
exports2.Result = Result11;
|
|
3969
3969
|
function checkResultErrors2(result) {
|
|
3970
3970
|
const errors2 = [];
|
|
3971
3971
|
const checkErrors = function(path2, object2) {
|
|
@@ -32403,8 +32403,8 @@ ${errorReport}`);
|
|
|
32403
32403
|
var UTXO_QUERY_MAX_RETRIES = 3;
|
|
32404
32404
|
var UTXO_QUERY_RETRY_DELAY_MS = 500;
|
|
32405
32405
|
var QUANTUM_WINDOW_SECONDS2 = 60;
|
|
32406
|
-
var
|
|
32407
|
-
var SAFE_EXECUTION_WINDOW_SECONDS = QUANTUM_WINDOW_SECONDS2 -
|
|
32406
|
+
var DEAD_ZONE_SECONDS2 = 16;
|
|
32407
|
+
var SAFE_EXECUTION_WINDOW_SECONDS = QUANTUM_WINDOW_SECONDS2 - DEAD_ZONE_SECONDS2;
|
|
32408
32408
|
var SECONDS_PER_DAY = 86400;
|
|
32409
32409
|
var DAYS_PER_MONTH = 30;
|
|
32410
32410
|
var LIT_ACTION_ETH_RPC_TIMEOUT_MS = 8e3;
|
|
@@ -34943,8 +34943,8 @@ function getMainnetConfig() {
|
|
|
34943
34943
|
bitcoinWithdrawalAddressRegistry: MAINNET_CONTRACTS.BitcoinWithdrawalAddressRegistry || ""
|
|
34944
34944
|
},
|
|
34945
34945
|
subgraphs: {
|
|
34946
|
-
diamondHandsUrl: "https://
|
|
34947
|
-
//
|
|
34946
|
+
diamondHandsUrl: "https://gateway-arbitrum.network.thegraph.com/api/subgraphs/id/CCTPsdYqco2jChDLLBQTbdJWwoukVoMt1cXeR9ti6r9A"
|
|
34947
|
+
// Published Sepolia subgraph on Arbitrum One
|
|
34948
34948
|
},
|
|
34949
34949
|
litNetwork: "chipotle",
|
|
34950
34950
|
debug: false
|
|
@@ -90299,7 +90299,7 @@ __export(src_exports, {
|
|
|
90299
90299
|
ErrorSeverity: () => ErrorSeverity,
|
|
90300
90300
|
EventHelpers: () => EventHelpers,
|
|
90301
90301
|
LOCALHOST_CONTRACTS: () => LOCALHOST_CONTRACTS,
|
|
90302
|
-
LRUCache: () =>
|
|
90302
|
+
LRUCache: () => LRUCache,
|
|
90303
90303
|
LoanCreator: () => LoanCreator,
|
|
90304
90304
|
LoanQuery: () => LoanQuery,
|
|
90305
90305
|
LoanStatus: () => LoanStatus,
|
|
@@ -108080,8 +108080,11 @@ async function resolveEip1559FeeFields(provider) {
|
|
|
108080
108080
|
let maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ?? void 0;
|
|
108081
108081
|
if (!maxFeePerGas || !maxPriorityFeePerGas) {
|
|
108082
108082
|
const gasPrice = (await provider.getFeeData()).gasPrice ?? parseUnits("1", "gwei");
|
|
108083
|
-
maxFeePerGas = maxFeePerGas
|
|
108084
|
-
maxPriorityFeePerGas = maxPriorityFeePerGas
|
|
108083
|
+
maxFeePerGas = maxFeePerGas || gasPrice * 2n;
|
|
108084
|
+
maxPriorityFeePerGas = maxPriorityFeePerGas || parseUnits("1.5", "gwei");
|
|
108085
|
+
}
|
|
108086
|
+
if (maxFeePerGas < maxPriorityFeePerGas) {
|
|
108087
|
+
maxFeePerGas = maxPriorityFeePerGas;
|
|
108085
108088
|
}
|
|
108086
108089
|
return { maxFeePerGas, maxPriorityFeePerGas };
|
|
108087
108090
|
}
|
|
@@ -108186,6 +108189,9 @@ function validateSDKConfig(config) {
|
|
|
108186
108189
|
|
|
108187
108190
|
// src/utils/quantum-timing.ts
|
|
108188
108191
|
var QUANTUM_WINDOW_SECONDS = 60;
|
|
108192
|
+
var DEAD_ZONE_SECONDS = 8;
|
|
108193
|
+
var INCLUSION_LATENCY_BUDGET = 16;
|
|
108194
|
+
var POST_BOUNDARY_SKEW_MARGIN = 3;
|
|
108189
108195
|
function calculateNextQuantumTimestamp() {
|
|
108190
108196
|
const now = Math.floor(Date.now() / 1e3);
|
|
108191
108197
|
const currentQuantum = Math.floor(now / QUANTUM_WINDOW_SECONDS) * QUANTUM_WINDOW_SECONDS;
|
|
@@ -108214,6 +108220,27 @@ function validateQuantumTiming(signedTimestamp, _bufferSeconds = 30) {
|
|
|
108214
108220
|
console.log(" Current quantum:", currentQuantum);
|
|
108215
108221
|
console.log(" Valid window: PAST/CURRENT/NEXT (180s total)");
|
|
108216
108222
|
}
|
|
108223
|
+
async function awaitSafeSubmissionWindow(quantumTimestamp, opts = {}) {
|
|
108224
|
+
const now = opts.now ?? (() => Math.floor(Date.now() / 1e3));
|
|
108225
|
+
const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
108226
|
+
const nowSec = now();
|
|
108227
|
+
const signatureQuantum = Math.floor(quantumTimestamp / QUANTUM_WINDOW_SECONDS) * QUANTUM_WINDOW_SECONDS;
|
|
108228
|
+
const currentQuantum = Math.floor(nowSec / QUANTUM_WINDOW_SECONDS) * QUANTUM_WINDOW_SECONDS;
|
|
108229
|
+
const secsToBoundary = QUANTUM_WINDOW_SECONDS - nowSec % QUANTUM_WINDOW_SECONDS;
|
|
108230
|
+
const isNextQuantumSig = signatureQuantum === currentQuantum + QUANTUM_WINDOW_SECONDS;
|
|
108231
|
+
if (isNextQuantumSig && secsToBoundary <= DEAD_ZONE_SECONDS + INCLUSION_LATENCY_BUDGET) {
|
|
108232
|
+
const target = currentQuantum + QUANTUM_WINDOW_SECONDS + POST_BOUNDARY_SKEW_MARGIN;
|
|
108233
|
+
const waitSeconds = target - nowSec;
|
|
108234
|
+
if (waitSeconds > 0) {
|
|
108235
|
+
console.log(
|
|
108236
|
+
`[Quantum Timing] \u23F3 Deferring send ${waitSeconds}s to clear the quantum dead zone (sig quantum ${signatureQuantum}, current ${currentQuantum}, ${secsToBoundary}s to boundary)`
|
|
108237
|
+
);
|
|
108238
|
+
await sleep(waitSeconds * 1e3);
|
|
108239
|
+
return { waited: true, waitedSeconds: waitSeconds };
|
|
108240
|
+
}
|
|
108241
|
+
}
|
|
108242
|
+
return { waited: false, waitedSeconds: 0 };
|
|
108243
|
+
}
|
|
108217
108244
|
|
|
108218
108245
|
// src/utils/mint-authorization.utils.ts
|
|
108219
108246
|
var PKP_NFT_ABI = [
|
|
@@ -109823,106 +109850,365 @@ function createContractManager(config) {
|
|
|
109823
109850
|
}
|
|
109824
109851
|
|
|
109825
109852
|
// src/modules/cache/cache-manager.module.ts
|
|
109826
|
-
var
|
|
109827
|
-
cache
|
|
109853
|
+
var LRUCache = class {
|
|
109854
|
+
cache;
|
|
109855
|
+
/**
|
|
109856
|
+
* Audit M-J: singleflight registry for `getOrCompute` / `getOrComputeResult`.
|
|
109857
|
+
* Concurrent cache-miss callers for the same key share one inflight promise
|
|
109858
|
+
* instead of each running `compute()` independently — important when the
|
|
109859
|
+
* compute spends a paid LIT capacity credit or hits a rate-limited upstream.
|
|
109860
|
+
*/
|
|
109861
|
+
inflight = /* @__PURE__ */ new Map();
|
|
109862
|
+
inflightResult = /* @__PURE__ */ new Map();
|
|
109828
109863
|
maxSize;
|
|
109829
109864
|
ttlMs;
|
|
109830
|
-
|
|
109831
|
-
|
|
109832
|
-
|
|
109865
|
+
debug;
|
|
109866
|
+
name;
|
|
109867
|
+
// Statistics
|
|
109868
|
+
stats = {
|
|
109869
|
+
hits: 0,
|
|
109870
|
+
misses: 0,
|
|
109871
|
+
evictions: 0
|
|
109872
|
+
};
|
|
109873
|
+
constructor(config = {}) {
|
|
109874
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
109875
|
+
this.maxSize = config.maxSize || 1e3;
|
|
109876
|
+
this.ttlMs = config.ttlMs || 6e4;
|
|
109877
|
+
this.debug = config.debug || false;
|
|
109878
|
+
this.name = config.name || "Cache";
|
|
109879
|
+
if (this.debug) {
|
|
109880
|
+
console.log(
|
|
109881
|
+
`\u{1F4BE} [${this.name}] Initialized: maxSize=${this.maxSize}, ttl=${this.ttlMs}ms`
|
|
109882
|
+
);
|
|
109883
|
+
}
|
|
109833
109884
|
}
|
|
109834
109885
|
/**
|
|
109835
109886
|
* Get value from cache
|
|
109887
|
+
*
|
|
109888
|
+
* Returns null if:
|
|
109889
|
+
* - Key not found
|
|
109890
|
+
* - Entry has expired
|
|
109891
|
+
*
|
|
109892
|
+
* @param key - Cache key
|
|
109893
|
+
* @returns Cached value or null
|
|
109836
109894
|
*/
|
|
109837
109895
|
get(key) {
|
|
109838
109896
|
const entry = this.cache.get(key);
|
|
109839
109897
|
if (!entry) {
|
|
109840
|
-
|
|
109898
|
+
this.stats.misses++;
|
|
109899
|
+
if (this.debug) {
|
|
109900
|
+
console.log(`\u274C [${this.name}] Cache MISS: ${String(key)}`);
|
|
109901
|
+
}
|
|
109902
|
+
return null;
|
|
109841
109903
|
}
|
|
109842
|
-
|
|
109843
|
-
if (now - entry.timestamp > entry.ttl) {
|
|
109904
|
+
if (this.isExpired(entry)) {
|
|
109844
109905
|
this.cache.delete(key);
|
|
109845
|
-
|
|
109906
|
+
this.stats.misses++;
|
|
109907
|
+
if (this.debug) {
|
|
109908
|
+
const age = Date.now() - entry.timestamp;
|
|
109909
|
+
console.log(`\u23F0 [${this.name}] Cache EXPIRED: ${String(key)} (age: ${age}ms)`);
|
|
109910
|
+
}
|
|
109911
|
+
return null;
|
|
109912
|
+
}
|
|
109913
|
+
entry.hits++;
|
|
109914
|
+
entry.lastAccessed = Date.now();
|
|
109915
|
+
this.cache.set(key, entry);
|
|
109916
|
+
this.stats.hits++;
|
|
109917
|
+
if (this.debug) {
|
|
109918
|
+
const age = Date.now() - entry.timestamp;
|
|
109919
|
+
console.log(
|
|
109920
|
+
`\u2705 [${this.name}] Cache HIT: ${String(key)} (age: ${age}ms, hits: ${entry.hits})`
|
|
109921
|
+
);
|
|
109846
109922
|
}
|
|
109847
109923
|
return entry.value;
|
|
109848
109924
|
}
|
|
109925
|
+
/**
|
|
109926
|
+
* Get value from cache with Result wrapper
|
|
109927
|
+
*
|
|
109928
|
+
* Useful when you want to distinguish between "not found" and "expired"
|
|
109929
|
+
*/
|
|
109930
|
+
getResult(key) {
|
|
109931
|
+
const value = this.get(key);
|
|
109932
|
+
if (value === null) {
|
|
109933
|
+
return failure(
|
|
109934
|
+
new SDKError({
|
|
109935
|
+
message: `Cache miss for key: ${String(key)}`,
|
|
109936
|
+
category: "CACHE" /* CACHE */,
|
|
109937
|
+
severity: "LOW" /* LOW */,
|
|
109938
|
+
originalError: new Error("Cache miss")
|
|
109939
|
+
})
|
|
109940
|
+
);
|
|
109941
|
+
}
|
|
109942
|
+
return success(value);
|
|
109943
|
+
}
|
|
109849
109944
|
/**
|
|
109850
109945
|
* Set value in cache
|
|
109946
|
+
*
|
|
109947
|
+
* If cache is full, evicts the least recently used entry
|
|
109948
|
+
*
|
|
109949
|
+
* @param key - Cache key
|
|
109950
|
+
* @param value - Value to cache
|
|
109951
|
+
* @param ttl - Optional custom TTL for this entry (ms)
|
|
109851
109952
|
*/
|
|
109852
109953
|
set(key, value, ttl) {
|
|
109853
109954
|
if (this.cache.size >= this.maxSize && !this.cache.has(key)) {
|
|
109854
|
-
|
|
109855
|
-
if (firstKey) {
|
|
109856
|
-
this.cache.delete(firstKey);
|
|
109857
|
-
}
|
|
109955
|
+
this.evictLRU();
|
|
109858
109956
|
}
|
|
109859
|
-
|
|
109957
|
+
const entry = {
|
|
109860
109958
|
value,
|
|
109861
109959
|
timestamp: Date.now(),
|
|
109862
|
-
|
|
109863
|
-
|
|
109960
|
+
hits: 0,
|
|
109961
|
+
lastAccessed: Date.now()
|
|
109962
|
+
};
|
|
109963
|
+
this.cache.set(key, entry);
|
|
109964
|
+
if (this.debug) {
|
|
109965
|
+
const effectiveTtl = ttl || this.ttlMs;
|
|
109966
|
+
console.log(
|
|
109967
|
+
`\u{1F4BE} [${this.name}] Cache SET: ${String(key)} (ttl: ${effectiveTtl}ms, size: ${this.cache.size}/${this.maxSize})`
|
|
109968
|
+
);
|
|
109969
|
+
}
|
|
109864
109970
|
}
|
|
109865
109971
|
/**
|
|
109866
|
-
*
|
|
109972
|
+
* Set value in cache with Result wrapper
|
|
109973
|
+
*/
|
|
109974
|
+
setResult(key, value, ttl) {
|
|
109975
|
+
try {
|
|
109976
|
+
this.set(key, value, ttl);
|
|
109977
|
+
return success(void 0);
|
|
109978
|
+
} catch (error2) {
|
|
109979
|
+
return failure(
|
|
109980
|
+
new SDKError({
|
|
109981
|
+
message: `Failed to set cache value for key: ${String(key)}`,
|
|
109982
|
+
category: "CACHE" /* CACHE */,
|
|
109983
|
+
severity: "MEDIUM" /* MEDIUM */,
|
|
109984
|
+
originalError: error2 instanceof Error ? error2 : new Error(String(error2))
|
|
109985
|
+
})
|
|
109986
|
+
);
|
|
109987
|
+
}
|
|
109988
|
+
}
|
|
109989
|
+
/**
|
|
109990
|
+
* Check if key exists in cache (without affecting stats)
|
|
109867
109991
|
*/
|
|
109868
109992
|
has(key) {
|
|
109869
|
-
|
|
109993
|
+
const entry = this.cache.get(key);
|
|
109994
|
+
return entry !== void 0 && !this.isExpired(entry);
|
|
109870
109995
|
}
|
|
109871
109996
|
/**
|
|
109872
|
-
* Delete key from cache
|
|
109997
|
+
* Delete specific key from cache
|
|
109873
109998
|
*/
|
|
109874
109999
|
delete(key) {
|
|
109875
|
-
|
|
110000
|
+
const deleted = this.cache.delete(key);
|
|
110001
|
+
if (deleted && this.debug) {
|
|
110002
|
+
console.log(`\u{1F5D1}\uFE0F [${this.name}] Cache DELETE: ${String(key)}`);
|
|
110003
|
+
}
|
|
110004
|
+
return deleted;
|
|
109876
110005
|
}
|
|
109877
110006
|
/**
|
|
109878
|
-
* Clear
|
|
110007
|
+
* Clear entire cache
|
|
109879
110008
|
*/
|
|
109880
110009
|
clear() {
|
|
110010
|
+
const previousSize = this.cache.size;
|
|
109881
110011
|
this.cache.clear();
|
|
110012
|
+
this.stats = {
|
|
110013
|
+
hits: 0,
|
|
110014
|
+
misses: 0,
|
|
110015
|
+
evictions: 0
|
|
110016
|
+
};
|
|
110017
|
+
if (this.debug) {
|
|
110018
|
+
console.log(`\u{1F9F9} [${this.name}] Cache CLEARED: removed ${previousSize} entries`);
|
|
110019
|
+
}
|
|
109882
110020
|
}
|
|
109883
110021
|
/**
|
|
109884
|
-
*
|
|
110022
|
+
* Get current cache size
|
|
110023
|
+
*/
|
|
110024
|
+
size() {
|
|
110025
|
+
return this.cache.size;
|
|
110026
|
+
}
|
|
110027
|
+
/**
|
|
110028
|
+
* Get cache statistics
|
|
110029
|
+
*/
|
|
110030
|
+
getStats() {
|
|
110031
|
+
const entries = Array.from(this.cache.values());
|
|
110032
|
+
const timestamps = entries.map((e) => e.timestamp);
|
|
110033
|
+
const total = this.stats.hits + this.stats.misses;
|
|
110034
|
+
const hitRate = total === 0 ? 0 : this.stats.hits / total * 100;
|
|
110035
|
+
return {
|
|
110036
|
+
size: this.cache.size,
|
|
110037
|
+
hits: this.stats.hits,
|
|
110038
|
+
misses: this.stats.misses,
|
|
110039
|
+
evictions: this.stats.evictions,
|
|
110040
|
+
oldestEntry: timestamps.length > 0 ? Math.min(...timestamps) : 0,
|
|
110041
|
+
newestEntry: timestamps.length > 0 ? Math.max(...timestamps) : 0,
|
|
110042
|
+
hitRate
|
|
110043
|
+
};
|
|
110044
|
+
}
|
|
110045
|
+
/**
|
|
110046
|
+
* Get hit rate percentage
|
|
110047
|
+
*/
|
|
110048
|
+
getHitRate() {
|
|
110049
|
+
const total = this.stats.hits + this.stats.misses;
|
|
110050
|
+
return total === 0 ? 0 : this.stats.hits / total * 100;
|
|
110051
|
+
}
|
|
110052
|
+
/**
|
|
110053
|
+
* Get all cached keys (for debugging)
|
|
110054
|
+
*/
|
|
110055
|
+
getKeys() {
|
|
110056
|
+
return Array.from(this.cache.keys());
|
|
110057
|
+
}
|
|
110058
|
+
/**
|
|
110059
|
+
* Get all cached values (for debugging)
|
|
110060
|
+
*/
|
|
110061
|
+
getValues() {
|
|
110062
|
+
return Array.from(this.cache.values()).map((entry) => entry.value);
|
|
110063
|
+
}
|
|
110064
|
+
/**
|
|
110065
|
+
* Get all cache entries with metadata (for debugging)
|
|
110066
|
+
*/
|
|
110067
|
+
getEntries() {
|
|
110068
|
+
return Array.from(this.cache.entries()).map(([key, entry]) => ({
|
|
110069
|
+
key,
|
|
110070
|
+
value: entry.value,
|
|
110071
|
+
metadata: {
|
|
110072
|
+
timestamp: entry.timestamp,
|
|
110073
|
+
hits: entry.hits,
|
|
110074
|
+
lastAccessed: entry.lastAccessed
|
|
110075
|
+
}
|
|
110076
|
+
}));
|
|
110077
|
+
}
|
|
110078
|
+
/**
|
|
110079
|
+
* Clean up expired entries
|
|
110080
|
+
*
|
|
110081
|
+
* Useful for periodic maintenance
|
|
110082
|
+
*
|
|
110083
|
+
* @returns Number of entries cleaned
|
|
109885
110084
|
*/
|
|
109886
110085
|
cleanExpired() {
|
|
109887
110086
|
const now = Date.now();
|
|
109888
|
-
let
|
|
110087
|
+
let cleanedCount = 0;
|
|
109889
110088
|
for (const [key, entry] of this.cache.entries()) {
|
|
109890
|
-
if (now - entry.timestamp >
|
|
110089
|
+
if (now - entry.timestamp > this.ttlMs) {
|
|
109891
110090
|
this.cache.delete(key);
|
|
109892
|
-
|
|
110091
|
+
cleanedCount++;
|
|
109893
110092
|
}
|
|
109894
110093
|
}
|
|
109895
|
-
|
|
110094
|
+
if (cleanedCount > 0 && this.debug) {
|
|
110095
|
+
console.log(`\u{1F9F9} [${this.name}] Cleaned ${cleanedCount} expired entries`);
|
|
110096
|
+
}
|
|
110097
|
+
return cleanedCount;
|
|
109896
110098
|
}
|
|
109897
110099
|
/**
|
|
109898
|
-
*
|
|
110100
|
+
* Check if cache entry is expired
|
|
109899
110101
|
*/
|
|
109900
|
-
|
|
109901
|
-
return
|
|
109902
|
-
|
|
109903
|
-
|
|
109904
|
-
|
|
109905
|
-
|
|
110102
|
+
isExpired(entry) {
|
|
110103
|
+
return Date.now() - entry.timestamp > this.ttlMs;
|
|
110104
|
+
}
|
|
110105
|
+
/**
|
|
110106
|
+
* Evict least recently used entry
|
|
110107
|
+
*/
|
|
110108
|
+
evictLRU() {
|
|
110109
|
+
let oldestKey = null;
|
|
110110
|
+
let oldestAccess = Infinity;
|
|
110111
|
+
for (const [key, entry] of this.cache.entries()) {
|
|
110112
|
+
if (entry.lastAccessed < oldestAccess) {
|
|
110113
|
+
oldestAccess = entry.lastAccessed;
|
|
110114
|
+
oldestKey = key;
|
|
110115
|
+
}
|
|
110116
|
+
}
|
|
110117
|
+
if (oldestKey !== null) {
|
|
110118
|
+
this.cache.delete(oldestKey);
|
|
110119
|
+
this.stats.evictions++;
|
|
110120
|
+
if (this.debug) {
|
|
110121
|
+
const timeSinceAccess = Date.now() - oldestAccess;
|
|
110122
|
+
console.log(
|
|
110123
|
+
`\u267B\uFE0F [${this.name}] Cache EVICT (LRU): ${String(oldestKey)} (last accessed: ${timeSinceAccess}ms ago)`
|
|
110124
|
+
);
|
|
110125
|
+
}
|
|
110126
|
+
}
|
|
110127
|
+
}
|
|
110128
|
+
/**
|
|
110129
|
+
* Get or compute value
|
|
110130
|
+
*
|
|
110131
|
+
* If key exists in cache, returns cached value.
|
|
110132
|
+
* Otherwise, computes value using provided function and caches it.
|
|
110133
|
+
*
|
|
110134
|
+
* @param key - Cache key
|
|
110135
|
+
* @param compute - Function to compute value if not in cache
|
|
110136
|
+
* @param ttl - Optional custom TTL for this entry
|
|
110137
|
+
* @returns Cached or computed value
|
|
110138
|
+
*/
|
|
110139
|
+
async getOrCompute(key, compute, ttl) {
|
|
110140
|
+
const cached = this.get(key);
|
|
110141
|
+
if (cached !== null) {
|
|
110142
|
+
return cached;
|
|
110143
|
+
}
|
|
110144
|
+
const existing = this.inflight.get(key);
|
|
110145
|
+
if (existing) {
|
|
110146
|
+
return existing;
|
|
110147
|
+
}
|
|
110148
|
+
const computePromise = (async () => {
|
|
110149
|
+
try {
|
|
110150
|
+
const value = await compute();
|
|
110151
|
+
this.set(key, value, ttl);
|
|
110152
|
+
return value;
|
|
110153
|
+
} finally {
|
|
110154
|
+
this.inflight.delete(key);
|
|
110155
|
+
}
|
|
110156
|
+
})();
|
|
110157
|
+
this.inflight.set(key, computePromise);
|
|
110158
|
+
return computePromise;
|
|
110159
|
+
}
|
|
110160
|
+
/**
|
|
110161
|
+
* Get or compute value with Result wrapper
|
|
110162
|
+
*/
|
|
110163
|
+
async getOrComputeResult(key, compute, ttl) {
|
|
110164
|
+
const cached = this.get(key);
|
|
110165
|
+
if (cached !== null) {
|
|
110166
|
+
return success(cached);
|
|
110167
|
+
}
|
|
110168
|
+
const existing = this.inflightResult.get(key);
|
|
110169
|
+
if (existing) {
|
|
110170
|
+
return existing;
|
|
110171
|
+
}
|
|
110172
|
+
const computePromise = (async () => {
|
|
110173
|
+
try {
|
|
110174
|
+
return await compute();
|
|
110175
|
+
} finally {
|
|
110176
|
+
this.inflightResult.delete(key);
|
|
110177
|
+
}
|
|
110178
|
+
})();
|
|
110179
|
+
this.inflightResult.set(key, computePromise);
|
|
110180
|
+
const result = await computePromise;
|
|
110181
|
+
if (result.success) {
|
|
110182
|
+
this.set(key, result.value, ttl);
|
|
110183
|
+
}
|
|
110184
|
+
return result;
|
|
109906
110185
|
}
|
|
109907
110186
|
};
|
|
109908
110187
|
var CacheManager = class {
|
|
109909
110188
|
caches = /* @__PURE__ */ new Map();
|
|
109910
|
-
|
|
109911
|
-
constructor(
|
|
109912
|
-
this.
|
|
110189
|
+
globalConfig;
|
|
110190
|
+
constructor(globalConfig = {}) {
|
|
110191
|
+
this.globalConfig = globalConfig;
|
|
109913
110192
|
}
|
|
109914
110193
|
/**
|
|
109915
|
-
*
|
|
110194
|
+
* Create or get a named cache
|
|
110195
|
+
*
|
|
110196
|
+
* @param name - Unique cache name
|
|
110197
|
+
* @param config - Optional cache-specific configuration
|
|
110198
|
+
* @returns LRU cache instance
|
|
109916
110199
|
*/
|
|
109917
110200
|
getCache(name, config) {
|
|
109918
|
-
|
|
109919
|
-
|
|
110201
|
+
const existingCache = this.caches.get(name);
|
|
110202
|
+
if (existingCache) {
|
|
110203
|
+
return existingCache;
|
|
109920
110204
|
}
|
|
109921
|
-
const
|
|
110205
|
+
const mergedConfig = {
|
|
110206
|
+
...this.globalConfig,
|
|
110207
|
+
...config,
|
|
110208
|
+
name
|
|
110209
|
+
};
|
|
110210
|
+
const cache = new LRUCache(mergedConfig);
|
|
109922
110211
|
this.caches.set(name, cache);
|
|
109923
|
-
if (this.debug) {
|
|
109924
|
-
console.log(`[CacheManager] Created cache: ${name}`, config);
|
|
109925
|
-
}
|
|
109926
110212
|
return cache;
|
|
109927
110213
|
}
|
|
109928
110214
|
/**
|
|
@@ -109937,11 +110223,11 @@ var CacheManager = class {
|
|
|
109937
110223
|
* Clean expired entries from all caches
|
|
109938
110224
|
*/
|
|
109939
110225
|
cleanAllExpired() {
|
|
109940
|
-
let
|
|
110226
|
+
let totalCleaned = 0;
|
|
109941
110227
|
for (const cache of this.caches.values()) {
|
|
109942
|
-
|
|
110228
|
+
totalCleaned += cache.cleanExpired();
|
|
109943
110229
|
}
|
|
109944
|
-
return
|
|
110230
|
+
return totalCleaned;
|
|
109945
110231
|
}
|
|
109946
110232
|
/**
|
|
109947
110233
|
* Get statistics for all caches
|
|
@@ -109954,11 +110240,16 @@ var CacheManager = class {
|
|
|
109954
110240
|
return stats;
|
|
109955
110241
|
}
|
|
109956
110242
|
/**
|
|
109957
|
-
*
|
|
110243
|
+
* Get list of all cache names
|
|
109958
110244
|
*/
|
|
109959
|
-
|
|
109960
|
-
this.
|
|
109961
|
-
|
|
110245
|
+
getCacheNames() {
|
|
110246
|
+
return Array.from(this.caches.keys());
|
|
110247
|
+
}
|
|
110248
|
+
/**
|
|
110249
|
+
* Delete a named cache
|
|
110250
|
+
*/
|
|
110251
|
+
deleteCache(name) {
|
|
110252
|
+
return this.caches.delete(name);
|
|
109962
110253
|
}
|
|
109963
110254
|
};
|
|
109964
110255
|
function createCacheManager(config) {
|
|
@@ -118451,12 +118742,11 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
|
|
|
118451
118742
|
{}
|
|
118452
118743
|
);
|
|
118453
118744
|
}
|
|
118454
|
-
|
|
118455
|
-
|
|
118456
|
-
|
|
118457
|
-
const errorMsg = error2.message || String(error2);
|
|
118745
|
+
const result = await this._requestMintUCDAttempt(request);
|
|
118746
|
+
if (!result.success && fullRetry < MAX_FULL_RETRIES) {
|
|
118747
|
+
const errorMsg = result.error || "";
|
|
118458
118748
|
const isStaleTimestamp = errorMsg.includes("quantumTimestamp too old") || errorMsg.includes("Timestamp staleness") || errorMsg.includes("MAX_SKEW") || errorMsg.includes("Quantum window expired") || errorMsg.includes("Too close to quantum boundary") || errorMsg.includes("QuantumOutsideWindow") || errorMsg.includes("Quantum window remaining too low");
|
|
118459
|
-
if (isStaleTimestamp
|
|
118749
|
+
if (isStaleTimestamp) {
|
|
118460
118750
|
if (this.config.debug) {
|
|
118461
118751
|
log.warn(
|
|
118462
118752
|
`\u26A0\uFE0F Timestamp became stale during mint process. Retrying from beginning...`,
|
|
@@ -118466,8 +118756,8 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
|
|
|
118466
118756
|
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
118467
118757
|
continue;
|
|
118468
118758
|
}
|
|
118469
|
-
throw error2;
|
|
118470
118759
|
}
|
|
118760
|
+
return result;
|
|
118471
118761
|
}
|
|
118472
118762
|
return {
|
|
118473
118763
|
success: false,
|
|
@@ -119089,6 +119379,7 @@ Context: Quantum timestamp=${validationResponse.timestamp}, Position=${request.p
|
|
|
119089
119379
|
"0x131d9a21": "QuantumExpired()",
|
|
119090
119380
|
"0x52ce5d58": "QuantumAlreadyUsed()",
|
|
119091
119381
|
"0x137f3b70": "InDeadZone()",
|
|
119382
|
+
"0xbe4b82c1": "DeadZoneViolation()",
|
|
119092
119383
|
"0x3e76a3c9": "QuantumOutsideWindow()",
|
|
119093
119384
|
"0x62278171": "InvalidValidatorSignature()",
|
|
119094
119385
|
"0xb9d419a7": "DebtUpdateVerificationFailed()",
|
|
@@ -119109,7 +119400,7 @@ Mint/debt diagnostics (LoanOperationsManager mint path \u2192 increaseDebtFromMi
|
|
|
119109
119400
|
Contract expects UCD supply increase to match mintAmount+mintFee and debt update to newDebt.
|
|
119110
119401
|
` : "";
|
|
119111
119402
|
let quantumContext = "";
|
|
119112
|
-
if (selector === "0x131d9a21" || selector === "0x52ce5d58" || selector === "0x137f3b70" || selector === "0x3e76a3c9") {
|
|
119403
|
+
if (selector === "0x131d9a21" || selector === "0x52ce5d58" || selector === "0x137f3b70" || selector === "0xbe4b82c1" || selector === "0x3e76a3c9") {
|
|
119113
119404
|
const currentTime2 = Math.floor(Date.now() / 1e3);
|
|
119114
119405
|
const currentQuantum = Math.floor(currentTime2 / 60) * 60;
|
|
119115
119406
|
const sigQuantum2 = Math.floor(validationResponse.timestamp / 60) * 60;
|
|
@@ -119371,6 +119662,7 @@ Position: ${request.positionId}`
|
|
|
119371
119662
|
validationResponse.timestamp,
|
|
119372
119663
|
signatureHexMint
|
|
119373
119664
|
]);
|
|
119665
|
+
await awaitSafeSubmissionWindow(Number(validationResponse.timestamp));
|
|
119374
119666
|
const fromAddress = await signer.getAddress();
|
|
119375
119667
|
const estimatedGas = await estimateContractCallGasWithMargin(
|
|
119376
119668
|
signerProvider,
|
|
@@ -119429,6 +119721,7 @@ Position: ${request.positionId}`
|
|
|
119429
119721
|
"0x131d9a21": "QuantumExpired()",
|
|
119430
119722
|
"0x52ce5d58": "QuantumAlreadyUsed()",
|
|
119431
119723
|
"0x137f3b70": "InDeadZone()",
|
|
119724
|
+
"0xbe4b82c1": "DeadZoneViolation()",
|
|
119432
119725
|
"0x3e76a3c9": "QuantumOutsideWindow()",
|
|
119433
119726
|
"0x62278171": "InvalidValidatorSignature()",
|
|
119434
119727
|
"0xb9d419a7": "DebtUpdateVerificationFailed()",
|
|
@@ -119608,6 +119901,7 @@ Error data: ${errorData || "none"}`
|
|
|
119608
119901
|
"0x131d9a21": "QuantumExpired() - Signature quantum window has closed",
|
|
119609
119902
|
"0x52ce5d58": "QuantumAlreadyUsed() - This quantum was already used for this position",
|
|
119610
119903
|
"0x137f3b70": "InDeadZone() - Timestamp in dead zone (near quantum boundary)",
|
|
119904
|
+
"0xbe4b82c1": "DeadZoneViolation() - Non-current-quantum signature mined in the last 8s of the current quantum",
|
|
119611
119905
|
"0x3e76a3c9": "QuantumOutsideWindow() - Timestamp not in past/current/next quantum window"
|
|
119612
119906
|
};
|
|
119613
119907
|
const errorName = knownErrors[selector] || `Unknown error ${selector}`;
|
|
@@ -120676,6 +120970,7 @@ Error data: ${errorData || "none"}`
|
|
|
120676
120970
|
);
|
|
120677
120971
|
}
|
|
120678
120972
|
const positionManager = positionManagerResult.value;
|
|
120973
|
+
await awaitSafeSubmissionWindow(Number(quantumTimestamp));
|
|
120679
120974
|
const tx = await positionManager["extendPosition"](
|
|
120680
120975
|
positionIdBytes32,
|
|
120681
120976
|
BigInt(_selectedTerm),
|
|
@@ -121108,6 +121403,57 @@ Error data: ${errorData || "none"}`
|
|
|
121108
121403
|
if (!pauseCheck.ok) {
|
|
121109
121404
|
return { success: false, error: pauseCheck.error };
|
|
121110
121405
|
}
|
|
121406
|
+
const MAX_FULL_RETRIES = 3;
|
|
121407
|
+
for (let fullRetry = 1; fullRetry <= MAX_FULL_RETRIES; fullRetry++) {
|
|
121408
|
+
if (fullRetry > 1 && this.config.debug) {
|
|
121409
|
+
log.info(
|
|
121410
|
+
`\u{1F504} Full payment retry ${fullRetry}/${MAX_FULL_RETRIES} due to quantum-timing failure...`,
|
|
121411
|
+
{}
|
|
121412
|
+
);
|
|
121413
|
+
}
|
|
121414
|
+
const result = await this._makePaymentAttempt(request);
|
|
121415
|
+
if (fullRetry < MAX_FULL_RETRIES && this.isRetryablePaymentQuantumFailure(result)) {
|
|
121416
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
121417
|
+
continue;
|
|
121418
|
+
}
|
|
121419
|
+
return result;
|
|
121420
|
+
}
|
|
121421
|
+
return {
|
|
121422
|
+
success: false,
|
|
121423
|
+
error: "Max retries exceeded for payment operation"
|
|
121424
|
+
};
|
|
121425
|
+
} finally {
|
|
121426
|
+
this.invalidateCachesForPosition(request.positionId);
|
|
121427
|
+
this.releaseWriteLock(request.positionId);
|
|
121428
|
+
}
|
|
121429
|
+
}
|
|
121430
|
+
/**
|
|
121431
|
+
* Whether a failed payment attempt is a quantum-timing failure that a fresh
|
|
121432
|
+
* re-sign can fix (safe to retry), versus a terminal failure.
|
|
121433
|
+
*
|
|
121434
|
+
* Retryable: pre-send simulation quantum errors, or an atomic mined revert
|
|
121435
|
+
* (status 0) — no funds moved and the quantum was not recorded on-chain, so a
|
|
121436
|
+
* fresh signature + resubmit is safe.
|
|
121437
|
+
*
|
|
121438
|
+
* NOT retryable: a confirmation timeout — the original tx may still be pending, so
|
|
121439
|
+
* a resubmit could double-pay. It is surfaced (with its tx hash) instead.
|
|
121440
|
+
*/
|
|
121441
|
+
isRetryablePaymentQuantumFailure(result) {
|
|
121442
|
+
if (result.success || !result.error)
|
|
121443
|
+
return false;
|
|
121444
|
+
const e = result.error;
|
|
121445
|
+
if (e.includes("Transaction timeout"))
|
|
121446
|
+
return false;
|
|
121447
|
+
return e.includes("DeadZoneViolation") || e.includes("QuantumOutsideWindow") || e.includes("QuantumAlreadyUsed") || e.includes("QuantumExpired") || e === "Transaction reverted";
|
|
121448
|
+
}
|
|
121449
|
+
/**
|
|
121450
|
+
* One payment attempt: user auth → Lit Action authorization → dead-zone gate →
|
|
121451
|
+
* pre-send simulation → broadcast → confirmation. Always resolves to a
|
|
121452
|
+
* PartialPaymentResult (never throws to the caller); the makePayment wrapper owns
|
|
121453
|
+
* the write lock, the pause pre-check, and the bounded re-sign retry loop.
|
|
121454
|
+
*/
|
|
121455
|
+
async _makePaymentAttempt(request) {
|
|
121456
|
+
try {
|
|
121111
121457
|
if (this.config.debug) {
|
|
121112
121458
|
log.info(`\u{1F4B3} Making payment...`, {});
|
|
121113
121459
|
log.info(` Request object:`, { request });
|
|
@@ -121368,7 +121714,6 @@ Error data: ${errorData || "none"}`
|
|
|
121368
121714
|
error: `Failed to get PositionManager: ${positionManagerResult.error.message}`
|
|
121369
121715
|
};
|
|
121370
121716
|
}
|
|
121371
|
-
const positionManager = positionManagerResult.value;
|
|
121372
121717
|
if (this.config.debug) {
|
|
121373
121718
|
log.info(
|
|
121374
121719
|
` About to call toBytes32 with: ${request.positionId} (type: ${typeof request.positionId})`
|
|
@@ -121428,9 +121773,6 @@ Error data: ${errorData || "none"}`
|
|
|
121428
121773
|
currentQuantum
|
|
121429
121774
|
});
|
|
121430
121775
|
}
|
|
121431
|
-
if (this.config.debug) {
|
|
121432
|
-
log.info("\u23ED\uFE0F Skipping dead zone check to isolate BigNumber issue", {});
|
|
121433
|
-
}
|
|
121434
121776
|
if (this.config.debug) {
|
|
121435
121777
|
log.info("\u{1F50D} Final timestamp validation:", {
|
|
121436
121778
|
litActionTimestamp: litActionResult.timestamp,
|
|
@@ -121497,108 +121839,100 @@ Error data: ${errorData || "none"}`
|
|
|
121497
121839
|
quantumTimestamp: quantumTimestamp.toString()
|
|
121498
121840
|
});
|
|
121499
121841
|
}
|
|
121500
|
-
|
|
121501
|
-
|
|
121502
|
-
|
|
121503
|
-
|
|
121504
|
-
|
|
121505
|
-
|
|
121506
|
-
|
|
121507
|
-
|
|
121508
|
-
|
|
121509
|
-
|
|
121510
|
-
|
|
121511
|
-
|
|
121512
|
-
|
|
121513
|
-
|
|
121514
|
-
|
|
121515
|
-
|
|
121516
|
-
|
|
121517
|
-
|
|
121518
|
-
|
|
121519
|
-
|
|
121520
|
-
|
|
121521
|
-
|
|
121522
|
-
|
|
121523
|
-
|
|
121524
|
-
|
|
121525
|
-
|
|
121526
|
-
|
|
121527
|
-
)
|
|
121528
|
-
|
|
121529
|
-
|
|
121530
|
-
|
|
121531
|
-
|
|
121532
|
-
|
|
121533
|
-
|
|
121534
|
-
|
|
121535
|
-
|
|
121536
|
-
|
|
121537
|
-
|
|
121538
|
-
|
|
121539
|
-
|
|
121540
|
-
|
|
121541
|
-
|
|
121542
|
-
|
|
121543
|
-
|
|
121544
|
-
if (typeof quantumTimestampStr !== "string" || quantumTimestampStr === "[object Object]") {
|
|
121545
|
-
throw new Error(`Invalid quantumTimestamp: ${quantumTimestampStr}`);
|
|
121546
|
-
}
|
|
121547
|
-
if (typeof btcPriceStr !== "string" || btcPriceStr === "[object Object]") {
|
|
121548
|
-
throw new Error(`Invalid btcPrice: ${btcPriceStr}`);
|
|
121549
|
-
}
|
|
121550
|
-
if (this.config.debug) {
|
|
121551
|
-
log.info("\u{1F50D} Final parameter validation before contract call:", {
|
|
121552
|
-
positionIdBytes32: typeof positionIdBytes32,
|
|
121553
|
-
paymentAmountStr: typeof paymentAmountStr + " = " + paymentAmountStr.substring(0, 20),
|
|
121554
|
-
quantumTimestampStr: typeof quantumTimestampStr + " = " + quantumTimestampStr.substring(0, 20),
|
|
121555
|
-
btcPriceStr: typeof btcPriceStr + " = " + btcPriceStr.substring(0, 20),
|
|
121556
|
-
signature: typeof signature + " = " + signature.substring(0, 20)
|
|
121842
|
+
await awaitSafeSubmissionWindow(Number(quantumTimestamp));
|
|
121843
|
+
const paymentAmountStr = paymentAmountWei.toString();
|
|
121844
|
+
const quantumTimestampStr = quantumTimestamp.toString();
|
|
121845
|
+
const btcPriceStr = btcPrice.toString();
|
|
121846
|
+
const paymentContractAddress = this.getContractAddressesOrThrow().positionManager;
|
|
121847
|
+
const paymentSigner = this.getSignerOrThrow();
|
|
121848
|
+
const paymentFrom = await paymentSigner.getAddress();
|
|
121849
|
+
const paymentProvider = contractManager.getProvider();
|
|
121850
|
+
const paymentIface = new Interface([
|
|
121851
|
+
"function makePayment(bytes32 positionId, uint256 paymentAmount, uint256 quantumTimestamp, uint256 btcPrice, bytes calldata paymentValidatorSignature) external returns (bool)"
|
|
121852
|
+
]);
|
|
121853
|
+
const paymentCalldata = paymentIface.encodeFunctionData("makePayment", [
|
|
121854
|
+
positionIdBytes32,
|
|
121855
|
+
paymentAmountStr,
|
|
121856
|
+
quantumTimestampStr,
|
|
121857
|
+
btcPriceStr,
|
|
121858
|
+
signature
|
|
121859
|
+
]);
|
|
121860
|
+
const decodePaymentRevert = (e) => {
|
|
121861
|
+
const raw = e?.data ?? e?.info?.error?.data ?? e?.error?.data?.data ?? e?.error?.data;
|
|
121862
|
+
const data = typeof raw === "string" ? raw : void 0;
|
|
121863
|
+
if (!data || !data.startsWith("0x") || data.length < 10)
|
|
121864
|
+
return null;
|
|
121865
|
+
const selector = data.slice(0, 10);
|
|
121866
|
+
const map3 = {
|
|
121867
|
+
"0xbe4b82c1": "DeadZoneViolation()",
|
|
121868
|
+
"0x137f3b70": "InDeadZone()",
|
|
121869
|
+
"0x52ce5d58": "QuantumAlreadyUsed()",
|
|
121870
|
+
"0x3e76a3c9": "QuantumOutsideWindow()",
|
|
121871
|
+
"0x131d9a21": "QuantumExpired()",
|
|
121872
|
+
"0x8baa579f": "InvalidSignature()",
|
|
121873
|
+
"0x62278171": "InvalidValidatorSignature()",
|
|
121874
|
+
"0x3ee5aeb5": "OperationNotAuthorized()",
|
|
121875
|
+
"0x48f5c3ed": "Unauthorized()"
|
|
121876
|
+
};
|
|
121877
|
+
return map3[selector] ?? `Unknown error ${selector}`;
|
|
121878
|
+
};
|
|
121879
|
+
const MAX_DEADZONE_RESIMULATIONS = 3;
|
|
121880
|
+
for (let sim = 1; ; sim++) {
|
|
121881
|
+
try {
|
|
121882
|
+
await paymentProvider.call({
|
|
121883
|
+
to: paymentContractAddress,
|
|
121884
|
+
from: paymentFrom,
|
|
121885
|
+
data: paymentCalldata
|
|
121557
121886
|
});
|
|
121558
|
-
|
|
121559
|
-
|
|
121560
|
-
|
|
121561
|
-
|
|
121562
|
-
|
|
121563
|
-
|
|
121564
|
-
|
|
121565
|
-
|
|
121566
|
-
|
|
121567
|
-
|
|
121568
|
-
|
|
121569
|
-
|
|
121570
|
-
|
|
121571
|
-
|
|
121572
|
-
|
|
121573
|
-
{
|
|
121574
|
-
error: contractError instanceof Error ? contractError.message : String(contractError)
|
|
121887
|
+
break;
|
|
121888
|
+
} catch (simError) {
|
|
121889
|
+
const decoded = decodePaymentRevert(simError);
|
|
121890
|
+
if (decoded === "DeadZoneViolation()" && sim <= MAX_DEADZONE_RESIMULATIONS) {
|
|
121891
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
121892
|
+
const sigQuantum = Math.floor(Number(quantumTimestamp) / 60) * 60;
|
|
121893
|
+
const realCurrentQuantum = Math.floor(nowSec / 60) * 60;
|
|
121894
|
+
if (sigQuantum === realCurrentQuantum) {
|
|
121895
|
+
if (this.config.debug) {
|
|
121896
|
+
log.info(
|
|
121897
|
+
"\u21AA\uFE0F Simulated DeadZoneViolation is a stale-latest-block artifact (signature is the current quantum) \u2014 proceeding to broadcast",
|
|
121898
|
+
{}
|
|
121899
|
+
);
|
|
121900
|
+
}
|
|
121901
|
+
break;
|
|
121575
121902
|
}
|
|
121576
|
-
|
|
121577
|
-
|
|
121578
|
-
|
|
121579
|
-
|
|
121580
|
-
|
|
121581
|
-
|
|
121582
|
-
|
|
121583
|
-
|
|
121584
|
-
|
|
121585
|
-
|
|
121586
|
-
|
|
121587
|
-
|
|
121588
|
-
|
|
121589
|
-
|
|
121590
|
-
|
|
121591
|
-
|
|
121592
|
-
|
|
121593
|
-
|
|
121594
|
-
|
|
121595
|
-
|
|
121596
|
-
|
|
121597
|
-
log.info("\u2705 Raw transaction fallback succeeded", {
|
|
121598
|
-
txHash: tx.hash
|
|
121599
|
-
});
|
|
121903
|
+
const gate = await awaitSafeSubmissionWindow(Number(quantumTimestamp));
|
|
121904
|
+
if (gate.waited) {
|
|
121905
|
+
if (this.config.debug) {
|
|
121906
|
+
log.info(
|
|
121907
|
+
`\u{1F501} Re-simulating makePayment after crossing the quantum boundary (attempt ${sim}/${MAX_DEADZONE_RESIMULATIONS})`,
|
|
121908
|
+
{}
|
|
121909
|
+
);
|
|
121910
|
+
}
|
|
121911
|
+
continue;
|
|
121912
|
+
}
|
|
121913
|
+
}
|
|
121914
|
+
const label = decoded ?? simError?.reason ?? simError?.shortMessage ?? (simError instanceof Error ? simError.message : String(simError));
|
|
121915
|
+
if (this.config.debug) {
|
|
121916
|
+
log.error("\u274C makePayment pre-send simulation reverted", { error: label });
|
|
121917
|
+
}
|
|
121918
|
+
return {
|
|
121919
|
+
success: false,
|
|
121920
|
+
error: `Payment would revert (pre-send simulation): ${label}`,
|
|
121921
|
+
positionId: request.positionId,
|
|
121922
|
+
paymentAmountUCD: request.paymentAmount
|
|
121923
|
+
};
|
|
121600
121924
|
}
|
|
121601
121925
|
}
|
|
121926
|
+
const MAKE_PAYMENT_GAS_CEILING = 500000n;
|
|
121927
|
+
const tx = await sendEip1559Transaction({
|
|
121928
|
+
signer: paymentSigner,
|
|
121929
|
+
to: paymentContractAddress,
|
|
121930
|
+
data: paymentCalldata,
|
|
121931
|
+
gasLimit: MAKE_PAYMENT_GAS_CEILING
|
|
121932
|
+
});
|
|
121933
|
+
if (this.config.debug) {
|
|
121934
|
+
log.info("\u2705 makePayment broadcast", { txHash: tx.hash });
|
|
121935
|
+
}
|
|
121602
121936
|
if (this.config.debug) {
|
|
121603
121937
|
log.info(`\u{1F4E4} Transaction sent: ${tx.hash}`);
|
|
121604
121938
|
log.info("\u23F3 Waiting for transaction confirmation...");
|
|
@@ -121742,9 +122076,6 @@ Error data: ${errorData || "none"}`
|
|
|
121742
122076
|
result.effectiveGasPrice = receipt.effectiveGasPrice?.toString() || receipt.gasPrice?.toString();
|
|
121743
122077
|
}
|
|
121744
122078
|
return result;
|
|
121745
|
-
} finally {
|
|
121746
|
-
this.invalidateCachesForPosition(request.positionId);
|
|
121747
|
-
this.releaseWriteLock(request.positionId);
|
|
121748
122079
|
}
|
|
121749
122080
|
}
|
|
121750
122081
|
/**
|
|
@@ -122306,6 +122637,7 @@ Error data: ${errorData || "none"}`
|
|
|
122306
122637
|
utxoVout: withdrawalParams.utxoVout
|
|
122307
122638
|
});
|
|
122308
122639
|
}
|
|
122640
|
+
await awaitSafeSubmissionWindow(Number(withdrawalParams.quantumTimestamp));
|
|
122309
122641
|
let tx;
|
|
122310
122642
|
try {
|
|
122311
122643
|
tx = await positionManagerContract["withdrawBTC"](
|