@gvnrdao/dh-sdk 0.0.293 → 0.0.294
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 +500 -171
- package/dist/index.mjs +500 -171
- 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,
|
|
@@ -108186,6 +108186,9 @@ function validateSDKConfig(config) {
|
|
|
108186
108186
|
|
|
108187
108187
|
// src/utils/quantum-timing.ts
|
|
108188
108188
|
var QUANTUM_WINDOW_SECONDS = 60;
|
|
108189
|
+
var DEAD_ZONE_SECONDS = 8;
|
|
108190
|
+
var INCLUSION_LATENCY_BUDGET = 16;
|
|
108191
|
+
var POST_BOUNDARY_SKEW_MARGIN = 3;
|
|
108189
108192
|
function calculateNextQuantumTimestamp() {
|
|
108190
108193
|
const now = Math.floor(Date.now() / 1e3);
|
|
108191
108194
|
const currentQuantum = Math.floor(now / QUANTUM_WINDOW_SECONDS) * QUANTUM_WINDOW_SECONDS;
|
|
@@ -108214,6 +108217,27 @@ function validateQuantumTiming(signedTimestamp, _bufferSeconds = 30) {
|
|
|
108214
108217
|
console.log(" Current quantum:", currentQuantum);
|
|
108215
108218
|
console.log(" Valid window: PAST/CURRENT/NEXT (180s total)");
|
|
108216
108219
|
}
|
|
108220
|
+
async function awaitSafeSubmissionWindow(quantumTimestamp, opts = {}) {
|
|
108221
|
+
const now = opts.now ?? (() => Math.floor(Date.now() / 1e3));
|
|
108222
|
+
const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
108223
|
+
const nowSec = now();
|
|
108224
|
+
const signatureQuantum = Math.floor(quantumTimestamp / QUANTUM_WINDOW_SECONDS) * QUANTUM_WINDOW_SECONDS;
|
|
108225
|
+
const currentQuantum = Math.floor(nowSec / QUANTUM_WINDOW_SECONDS) * QUANTUM_WINDOW_SECONDS;
|
|
108226
|
+
const secsToBoundary = QUANTUM_WINDOW_SECONDS - nowSec % QUANTUM_WINDOW_SECONDS;
|
|
108227
|
+
const isNextQuantumSig = signatureQuantum === currentQuantum + QUANTUM_WINDOW_SECONDS;
|
|
108228
|
+
if (isNextQuantumSig && secsToBoundary <= DEAD_ZONE_SECONDS + INCLUSION_LATENCY_BUDGET) {
|
|
108229
|
+
const target = currentQuantum + QUANTUM_WINDOW_SECONDS + POST_BOUNDARY_SKEW_MARGIN;
|
|
108230
|
+
const waitSeconds = target - nowSec;
|
|
108231
|
+
if (waitSeconds > 0) {
|
|
108232
|
+
console.log(
|
|
108233
|
+
`[Quantum Timing] \u23F3 Deferring send ${waitSeconds}s to clear the quantum dead zone (sig quantum ${signatureQuantum}, current ${currentQuantum}, ${secsToBoundary}s to boundary)`
|
|
108234
|
+
);
|
|
108235
|
+
await sleep(waitSeconds * 1e3);
|
|
108236
|
+
return { waited: true, waitedSeconds: waitSeconds };
|
|
108237
|
+
}
|
|
108238
|
+
}
|
|
108239
|
+
return { waited: false, waitedSeconds: 0 };
|
|
108240
|
+
}
|
|
108217
108241
|
|
|
108218
108242
|
// src/utils/mint-authorization.utils.ts
|
|
108219
108243
|
var PKP_NFT_ABI = [
|
|
@@ -109823,106 +109847,365 @@ function createContractManager(config) {
|
|
|
109823
109847
|
}
|
|
109824
109848
|
|
|
109825
109849
|
// src/modules/cache/cache-manager.module.ts
|
|
109826
|
-
var
|
|
109827
|
-
cache
|
|
109850
|
+
var LRUCache = class {
|
|
109851
|
+
cache;
|
|
109852
|
+
/**
|
|
109853
|
+
* Audit M-J: singleflight registry for `getOrCompute` / `getOrComputeResult`.
|
|
109854
|
+
* Concurrent cache-miss callers for the same key share one inflight promise
|
|
109855
|
+
* instead of each running `compute()` independently — important when the
|
|
109856
|
+
* compute spends a paid LIT capacity credit or hits a rate-limited upstream.
|
|
109857
|
+
*/
|
|
109858
|
+
inflight = /* @__PURE__ */ new Map();
|
|
109859
|
+
inflightResult = /* @__PURE__ */ new Map();
|
|
109828
109860
|
maxSize;
|
|
109829
109861
|
ttlMs;
|
|
109830
|
-
|
|
109831
|
-
|
|
109832
|
-
|
|
109862
|
+
debug;
|
|
109863
|
+
name;
|
|
109864
|
+
// Statistics
|
|
109865
|
+
stats = {
|
|
109866
|
+
hits: 0,
|
|
109867
|
+
misses: 0,
|
|
109868
|
+
evictions: 0
|
|
109869
|
+
};
|
|
109870
|
+
constructor(config = {}) {
|
|
109871
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
109872
|
+
this.maxSize = config.maxSize || 1e3;
|
|
109873
|
+
this.ttlMs = config.ttlMs || 6e4;
|
|
109874
|
+
this.debug = config.debug || false;
|
|
109875
|
+
this.name = config.name || "Cache";
|
|
109876
|
+
if (this.debug) {
|
|
109877
|
+
console.log(
|
|
109878
|
+
`\u{1F4BE} [${this.name}] Initialized: maxSize=${this.maxSize}, ttl=${this.ttlMs}ms`
|
|
109879
|
+
);
|
|
109880
|
+
}
|
|
109833
109881
|
}
|
|
109834
109882
|
/**
|
|
109835
109883
|
* Get value from cache
|
|
109884
|
+
*
|
|
109885
|
+
* Returns null if:
|
|
109886
|
+
* - Key not found
|
|
109887
|
+
* - Entry has expired
|
|
109888
|
+
*
|
|
109889
|
+
* @param key - Cache key
|
|
109890
|
+
* @returns Cached value or null
|
|
109836
109891
|
*/
|
|
109837
109892
|
get(key) {
|
|
109838
109893
|
const entry = this.cache.get(key);
|
|
109839
109894
|
if (!entry) {
|
|
109840
|
-
|
|
109895
|
+
this.stats.misses++;
|
|
109896
|
+
if (this.debug) {
|
|
109897
|
+
console.log(`\u274C [${this.name}] Cache MISS: ${String(key)}`);
|
|
109898
|
+
}
|
|
109899
|
+
return null;
|
|
109841
109900
|
}
|
|
109842
|
-
|
|
109843
|
-
if (now - entry.timestamp > entry.ttl) {
|
|
109901
|
+
if (this.isExpired(entry)) {
|
|
109844
109902
|
this.cache.delete(key);
|
|
109845
|
-
|
|
109903
|
+
this.stats.misses++;
|
|
109904
|
+
if (this.debug) {
|
|
109905
|
+
const age = Date.now() - entry.timestamp;
|
|
109906
|
+
console.log(`\u23F0 [${this.name}] Cache EXPIRED: ${String(key)} (age: ${age}ms)`);
|
|
109907
|
+
}
|
|
109908
|
+
return null;
|
|
109909
|
+
}
|
|
109910
|
+
entry.hits++;
|
|
109911
|
+
entry.lastAccessed = Date.now();
|
|
109912
|
+
this.cache.set(key, entry);
|
|
109913
|
+
this.stats.hits++;
|
|
109914
|
+
if (this.debug) {
|
|
109915
|
+
const age = Date.now() - entry.timestamp;
|
|
109916
|
+
console.log(
|
|
109917
|
+
`\u2705 [${this.name}] Cache HIT: ${String(key)} (age: ${age}ms, hits: ${entry.hits})`
|
|
109918
|
+
);
|
|
109846
109919
|
}
|
|
109847
109920
|
return entry.value;
|
|
109848
109921
|
}
|
|
109922
|
+
/**
|
|
109923
|
+
* Get value from cache with Result wrapper
|
|
109924
|
+
*
|
|
109925
|
+
* Useful when you want to distinguish between "not found" and "expired"
|
|
109926
|
+
*/
|
|
109927
|
+
getResult(key) {
|
|
109928
|
+
const value = this.get(key);
|
|
109929
|
+
if (value === null) {
|
|
109930
|
+
return failure(
|
|
109931
|
+
new SDKError({
|
|
109932
|
+
message: `Cache miss for key: ${String(key)}`,
|
|
109933
|
+
category: "CACHE" /* CACHE */,
|
|
109934
|
+
severity: "LOW" /* LOW */,
|
|
109935
|
+
originalError: new Error("Cache miss")
|
|
109936
|
+
})
|
|
109937
|
+
);
|
|
109938
|
+
}
|
|
109939
|
+
return success(value);
|
|
109940
|
+
}
|
|
109849
109941
|
/**
|
|
109850
109942
|
* Set value in cache
|
|
109943
|
+
*
|
|
109944
|
+
* If cache is full, evicts the least recently used entry
|
|
109945
|
+
*
|
|
109946
|
+
* @param key - Cache key
|
|
109947
|
+
* @param value - Value to cache
|
|
109948
|
+
* @param ttl - Optional custom TTL for this entry (ms)
|
|
109851
109949
|
*/
|
|
109852
109950
|
set(key, value, ttl) {
|
|
109853
109951
|
if (this.cache.size >= this.maxSize && !this.cache.has(key)) {
|
|
109854
|
-
|
|
109855
|
-
if (firstKey) {
|
|
109856
|
-
this.cache.delete(firstKey);
|
|
109857
|
-
}
|
|
109952
|
+
this.evictLRU();
|
|
109858
109953
|
}
|
|
109859
|
-
|
|
109954
|
+
const entry = {
|
|
109860
109955
|
value,
|
|
109861
109956
|
timestamp: Date.now(),
|
|
109862
|
-
|
|
109863
|
-
|
|
109957
|
+
hits: 0,
|
|
109958
|
+
lastAccessed: Date.now()
|
|
109959
|
+
};
|
|
109960
|
+
this.cache.set(key, entry);
|
|
109961
|
+
if (this.debug) {
|
|
109962
|
+
const effectiveTtl = ttl || this.ttlMs;
|
|
109963
|
+
console.log(
|
|
109964
|
+
`\u{1F4BE} [${this.name}] Cache SET: ${String(key)} (ttl: ${effectiveTtl}ms, size: ${this.cache.size}/${this.maxSize})`
|
|
109965
|
+
);
|
|
109966
|
+
}
|
|
109864
109967
|
}
|
|
109865
109968
|
/**
|
|
109866
|
-
*
|
|
109969
|
+
* Set value in cache with Result wrapper
|
|
109970
|
+
*/
|
|
109971
|
+
setResult(key, value, ttl) {
|
|
109972
|
+
try {
|
|
109973
|
+
this.set(key, value, ttl);
|
|
109974
|
+
return success(void 0);
|
|
109975
|
+
} catch (error2) {
|
|
109976
|
+
return failure(
|
|
109977
|
+
new SDKError({
|
|
109978
|
+
message: `Failed to set cache value for key: ${String(key)}`,
|
|
109979
|
+
category: "CACHE" /* CACHE */,
|
|
109980
|
+
severity: "MEDIUM" /* MEDIUM */,
|
|
109981
|
+
originalError: error2 instanceof Error ? error2 : new Error(String(error2))
|
|
109982
|
+
})
|
|
109983
|
+
);
|
|
109984
|
+
}
|
|
109985
|
+
}
|
|
109986
|
+
/**
|
|
109987
|
+
* Check if key exists in cache (without affecting stats)
|
|
109867
109988
|
*/
|
|
109868
109989
|
has(key) {
|
|
109869
|
-
|
|
109990
|
+
const entry = this.cache.get(key);
|
|
109991
|
+
return entry !== void 0 && !this.isExpired(entry);
|
|
109870
109992
|
}
|
|
109871
109993
|
/**
|
|
109872
|
-
* Delete key from cache
|
|
109994
|
+
* Delete specific key from cache
|
|
109873
109995
|
*/
|
|
109874
109996
|
delete(key) {
|
|
109875
|
-
|
|
109997
|
+
const deleted = this.cache.delete(key);
|
|
109998
|
+
if (deleted && this.debug) {
|
|
109999
|
+
console.log(`\u{1F5D1}\uFE0F [${this.name}] Cache DELETE: ${String(key)}`);
|
|
110000
|
+
}
|
|
110001
|
+
return deleted;
|
|
109876
110002
|
}
|
|
109877
110003
|
/**
|
|
109878
|
-
* Clear
|
|
110004
|
+
* Clear entire cache
|
|
109879
110005
|
*/
|
|
109880
110006
|
clear() {
|
|
110007
|
+
const previousSize = this.cache.size;
|
|
109881
110008
|
this.cache.clear();
|
|
110009
|
+
this.stats = {
|
|
110010
|
+
hits: 0,
|
|
110011
|
+
misses: 0,
|
|
110012
|
+
evictions: 0
|
|
110013
|
+
};
|
|
110014
|
+
if (this.debug) {
|
|
110015
|
+
console.log(`\u{1F9F9} [${this.name}] Cache CLEARED: removed ${previousSize} entries`);
|
|
110016
|
+
}
|
|
109882
110017
|
}
|
|
109883
110018
|
/**
|
|
109884
|
-
*
|
|
110019
|
+
* Get current cache size
|
|
110020
|
+
*/
|
|
110021
|
+
size() {
|
|
110022
|
+
return this.cache.size;
|
|
110023
|
+
}
|
|
110024
|
+
/**
|
|
110025
|
+
* Get cache statistics
|
|
110026
|
+
*/
|
|
110027
|
+
getStats() {
|
|
110028
|
+
const entries = Array.from(this.cache.values());
|
|
110029
|
+
const timestamps = entries.map((e) => e.timestamp);
|
|
110030
|
+
const total = this.stats.hits + this.stats.misses;
|
|
110031
|
+
const hitRate = total === 0 ? 0 : this.stats.hits / total * 100;
|
|
110032
|
+
return {
|
|
110033
|
+
size: this.cache.size,
|
|
110034
|
+
hits: this.stats.hits,
|
|
110035
|
+
misses: this.stats.misses,
|
|
110036
|
+
evictions: this.stats.evictions,
|
|
110037
|
+
oldestEntry: timestamps.length > 0 ? Math.min(...timestamps) : 0,
|
|
110038
|
+
newestEntry: timestamps.length > 0 ? Math.max(...timestamps) : 0,
|
|
110039
|
+
hitRate
|
|
110040
|
+
};
|
|
110041
|
+
}
|
|
110042
|
+
/**
|
|
110043
|
+
* Get hit rate percentage
|
|
110044
|
+
*/
|
|
110045
|
+
getHitRate() {
|
|
110046
|
+
const total = this.stats.hits + this.stats.misses;
|
|
110047
|
+
return total === 0 ? 0 : this.stats.hits / total * 100;
|
|
110048
|
+
}
|
|
110049
|
+
/**
|
|
110050
|
+
* Get all cached keys (for debugging)
|
|
110051
|
+
*/
|
|
110052
|
+
getKeys() {
|
|
110053
|
+
return Array.from(this.cache.keys());
|
|
110054
|
+
}
|
|
110055
|
+
/**
|
|
110056
|
+
* Get all cached values (for debugging)
|
|
110057
|
+
*/
|
|
110058
|
+
getValues() {
|
|
110059
|
+
return Array.from(this.cache.values()).map((entry) => entry.value);
|
|
110060
|
+
}
|
|
110061
|
+
/**
|
|
110062
|
+
* Get all cache entries with metadata (for debugging)
|
|
110063
|
+
*/
|
|
110064
|
+
getEntries() {
|
|
110065
|
+
return Array.from(this.cache.entries()).map(([key, entry]) => ({
|
|
110066
|
+
key,
|
|
110067
|
+
value: entry.value,
|
|
110068
|
+
metadata: {
|
|
110069
|
+
timestamp: entry.timestamp,
|
|
110070
|
+
hits: entry.hits,
|
|
110071
|
+
lastAccessed: entry.lastAccessed
|
|
110072
|
+
}
|
|
110073
|
+
}));
|
|
110074
|
+
}
|
|
110075
|
+
/**
|
|
110076
|
+
* Clean up expired entries
|
|
110077
|
+
*
|
|
110078
|
+
* Useful for periodic maintenance
|
|
110079
|
+
*
|
|
110080
|
+
* @returns Number of entries cleaned
|
|
109885
110081
|
*/
|
|
109886
110082
|
cleanExpired() {
|
|
109887
110083
|
const now = Date.now();
|
|
109888
|
-
let
|
|
110084
|
+
let cleanedCount = 0;
|
|
109889
110085
|
for (const [key, entry] of this.cache.entries()) {
|
|
109890
|
-
if (now - entry.timestamp >
|
|
110086
|
+
if (now - entry.timestamp > this.ttlMs) {
|
|
109891
110087
|
this.cache.delete(key);
|
|
109892
|
-
|
|
110088
|
+
cleanedCount++;
|
|
109893
110089
|
}
|
|
109894
110090
|
}
|
|
109895
|
-
|
|
110091
|
+
if (cleanedCount > 0 && this.debug) {
|
|
110092
|
+
console.log(`\u{1F9F9} [${this.name}] Cleaned ${cleanedCount} expired entries`);
|
|
110093
|
+
}
|
|
110094
|
+
return cleanedCount;
|
|
109896
110095
|
}
|
|
109897
110096
|
/**
|
|
109898
|
-
*
|
|
110097
|
+
* Check if cache entry is expired
|
|
109899
110098
|
*/
|
|
109900
|
-
|
|
109901
|
-
return
|
|
109902
|
-
|
|
109903
|
-
|
|
109904
|
-
|
|
109905
|
-
|
|
110099
|
+
isExpired(entry) {
|
|
110100
|
+
return Date.now() - entry.timestamp > this.ttlMs;
|
|
110101
|
+
}
|
|
110102
|
+
/**
|
|
110103
|
+
* Evict least recently used entry
|
|
110104
|
+
*/
|
|
110105
|
+
evictLRU() {
|
|
110106
|
+
let oldestKey = null;
|
|
110107
|
+
let oldestAccess = Infinity;
|
|
110108
|
+
for (const [key, entry] of this.cache.entries()) {
|
|
110109
|
+
if (entry.lastAccessed < oldestAccess) {
|
|
110110
|
+
oldestAccess = entry.lastAccessed;
|
|
110111
|
+
oldestKey = key;
|
|
110112
|
+
}
|
|
110113
|
+
}
|
|
110114
|
+
if (oldestKey !== null) {
|
|
110115
|
+
this.cache.delete(oldestKey);
|
|
110116
|
+
this.stats.evictions++;
|
|
110117
|
+
if (this.debug) {
|
|
110118
|
+
const timeSinceAccess = Date.now() - oldestAccess;
|
|
110119
|
+
console.log(
|
|
110120
|
+
`\u267B\uFE0F [${this.name}] Cache EVICT (LRU): ${String(oldestKey)} (last accessed: ${timeSinceAccess}ms ago)`
|
|
110121
|
+
);
|
|
110122
|
+
}
|
|
110123
|
+
}
|
|
110124
|
+
}
|
|
110125
|
+
/**
|
|
110126
|
+
* Get or compute value
|
|
110127
|
+
*
|
|
110128
|
+
* If key exists in cache, returns cached value.
|
|
110129
|
+
* Otherwise, computes value using provided function and caches it.
|
|
110130
|
+
*
|
|
110131
|
+
* @param key - Cache key
|
|
110132
|
+
* @param compute - Function to compute value if not in cache
|
|
110133
|
+
* @param ttl - Optional custom TTL for this entry
|
|
110134
|
+
* @returns Cached or computed value
|
|
110135
|
+
*/
|
|
110136
|
+
async getOrCompute(key, compute, ttl) {
|
|
110137
|
+
const cached = this.get(key);
|
|
110138
|
+
if (cached !== null) {
|
|
110139
|
+
return cached;
|
|
110140
|
+
}
|
|
110141
|
+
const existing = this.inflight.get(key);
|
|
110142
|
+
if (existing) {
|
|
110143
|
+
return existing;
|
|
110144
|
+
}
|
|
110145
|
+
const computePromise = (async () => {
|
|
110146
|
+
try {
|
|
110147
|
+
const value = await compute();
|
|
110148
|
+
this.set(key, value, ttl);
|
|
110149
|
+
return value;
|
|
110150
|
+
} finally {
|
|
110151
|
+
this.inflight.delete(key);
|
|
110152
|
+
}
|
|
110153
|
+
})();
|
|
110154
|
+
this.inflight.set(key, computePromise);
|
|
110155
|
+
return computePromise;
|
|
110156
|
+
}
|
|
110157
|
+
/**
|
|
110158
|
+
* Get or compute value with Result wrapper
|
|
110159
|
+
*/
|
|
110160
|
+
async getOrComputeResult(key, compute, ttl) {
|
|
110161
|
+
const cached = this.get(key);
|
|
110162
|
+
if (cached !== null) {
|
|
110163
|
+
return success(cached);
|
|
110164
|
+
}
|
|
110165
|
+
const existing = this.inflightResult.get(key);
|
|
110166
|
+
if (existing) {
|
|
110167
|
+
return existing;
|
|
110168
|
+
}
|
|
110169
|
+
const computePromise = (async () => {
|
|
110170
|
+
try {
|
|
110171
|
+
return await compute();
|
|
110172
|
+
} finally {
|
|
110173
|
+
this.inflightResult.delete(key);
|
|
110174
|
+
}
|
|
110175
|
+
})();
|
|
110176
|
+
this.inflightResult.set(key, computePromise);
|
|
110177
|
+
const result = await computePromise;
|
|
110178
|
+
if (result.success) {
|
|
110179
|
+
this.set(key, result.value, ttl);
|
|
110180
|
+
}
|
|
110181
|
+
return result;
|
|
109906
110182
|
}
|
|
109907
110183
|
};
|
|
109908
110184
|
var CacheManager = class {
|
|
109909
110185
|
caches = /* @__PURE__ */ new Map();
|
|
109910
|
-
|
|
109911
|
-
constructor(
|
|
109912
|
-
this.
|
|
110186
|
+
globalConfig;
|
|
110187
|
+
constructor(globalConfig = {}) {
|
|
110188
|
+
this.globalConfig = globalConfig;
|
|
109913
110189
|
}
|
|
109914
110190
|
/**
|
|
109915
|
-
*
|
|
110191
|
+
* Create or get a named cache
|
|
110192
|
+
*
|
|
110193
|
+
* @param name - Unique cache name
|
|
110194
|
+
* @param config - Optional cache-specific configuration
|
|
110195
|
+
* @returns LRU cache instance
|
|
109916
110196
|
*/
|
|
109917
110197
|
getCache(name, config) {
|
|
109918
|
-
|
|
109919
|
-
|
|
110198
|
+
const existingCache = this.caches.get(name);
|
|
110199
|
+
if (existingCache) {
|
|
110200
|
+
return existingCache;
|
|
109920
110201
|
}
|
|
109921
|
-
const
|
|
110202
|
+
const mergedConfig = {
|
|
110203
|
+
...this.globalConfig,
|
|
110204
|
+
...config,
|
|
110205
|
+
name
|
|
110206
|
+
};
|
|
110207
|
+
const cache = new LRUCache(mergedConfig);
|
|
109922
110208
|
this.caches.set(name, cache);
|
|
109923
|
-
if (this.debug) {
|
|
109924
|
-
console.log(`[CacheManager] Created cache: ${name}`, config);
|
|
109925
|
-
}
|
|
109926
110209
|
return cache;
|
|
109927
110210
|
}
|
|
109928
110211
|
/**
|
|
@@ -109937,11 +110220,11 @@ var CacheManager = class {
|
|
|
109937
110220
|
* Clean expired entries from all caches
|
|
109938
110221
|
*/
|
|
109939
110222
|
cleanAllExpired() {
|
|
109940
|
-
let
|
|
110223
|
+
let totalCleaned = 0;
|
|
109941
110224
|
for (const cache of this.caches.values()) {
|
|
109942
|
-
|
|
110225
|
+
totalCleaned += cache.cleanExpired();
|
|
109943
110226
|
}
|
|
109944
|
-
return
|
|
110227
|
+
return totalCleaned;
|
|
109945
110228
|
}
|
|
109946
110229
|
/**
|
|
109947
110230
|
* Get statistics for all caches
|
|
@@ -109954,11 +110237,16 @@ var CacheManager = class {
|
|
|
109954
110237
|
return stats;
|
|
109955
110238
|
}
|
|
109956
110239
|
/**
|
|
109957
|
-
*
|
|
110240
|
+
* Get list of all cache names
|
|
109958
110241
|
*/
|
|
109959
|
-
|
|
109960
|
-
this.
|
|
109961
|
-
|
|
110242
|
+
getCacheNames() {
|
|
110243
|
+
return Array.from(this.caches.keys());
|
|
110244
|
+
}
|
|
110245
|
+
/**
|
|
110246
|
+
* Delete a named cache
|
|
110247
|
+
*/
|
|
110248
|
+
deleteCache(name) {
|
|
110249
|
+
return this.caches.delete(name);
|
|
109962
110250
|
}
|
|
109963
110251
|
};
|
|
109964
110252
|
function createCacheManager(config) {
|
|
@@ -118451,12 +118739,11 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
|
|
|
118451
118739
|
{}
|
|
118452
118740
|
);
|
|
118453
118741
|
}
|
|
118454
|
-
|
|
118455
|
-
|
|
118456
|
-
|
|
118457
|
-
const errorMsg = error2.message || String(error2);
|
|
118742
|
+
const result = await this._requestMintUCDAttempt(request);
|
|
118743
|
+
if (!result.success && fullRetry < MAX_FULL_RETRIES) {
|
|
118744
|
+
const errorMsg = result.error || "";
|
|
118458
118745
|
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
|
|
118746
|
+
if (isStaleTimestamp) {
|
|
118460
118747
|
if (this.config.debug) {
|
|
118461
118748
|
log.warn(
|
|
118462
118749
|
`\u26A0\uFE0F Timestamp became stale during mint process. Retrying from beginning...`,
|
|
@@ -118466,8 +118753,8 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
|
|
|
118466
118753
|
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
118467
118754
|
continue;
|
|
118468
118755
|
}
|
|
118469
|
-
throw error2;
|
|
118470
118756
|
}
|
|
118757
|
+
return result;
|
|
118471
118758
|
}
|
|
118472
118759
|
return {
|
|
118473
118760
|
success: false,
|
|
@@ -119089,6 +119376,7 @@ Context: Quantum timestamp=${validationResponse.timestamp}, Position=${request.p
|
|
|
119089
119376
|
"0x131d9a21": "QuantumExpired()",
|
|
119090
119377
|
"0x52ce5d58": "QuantumAlreadyUsed()",
|
|
119091
119378
|
"0x137f3b70": "InDeadZone()",
|
|
119379
|
+
"0xbe4b82c1": "DeadZoneViolation()",
|
|
119092
119380
|
"0x3e76a3c9": "QuantumOutsideWindow()",
|
|
119093
119381
|
"0x62278171": "InvalidValidatorSignature()",
|
|
119094
119382
|
"0xb9d419a7": "DebtUpdateVerificationFailed()",
|
|
@@ -119109,7 +119397,7 @@ Mint/debt diagnostics (LoanOperationsManager mint path \u2192 increaseDebtFromMi
|
|
|
119109
119397
|
Contract expects UCD supply increase to match mintAmount+mintFee and debt update to newDebt.
|
|
119110
119398
|
` : "";
|
|
119111
119399
|
let quantumContext = "";
|
|
119112
|
-
if (selector === "0x131d9a21" || selector === "0x52ce5d58" || selector === "0x137f3b70" || selector === "0x3e76a3c9") {
|
|
119400
|
+
if (selector === "0x131d9a21" || selector === "0x52ce5d58" || selector === "0x137f3b70" || selector === "0xbe4b82c1" || selector === "0x3e76a3c9") {
|
|
119113
119401
|
const currentTime2 = Math.floor(Date.now() / 1e3);
|
|
119114
119402
|
const currentQuantum = Math.floor(currentTime2 / 60) * 60;
|
|
119115
119403
|
const sigQuantum2 = Math.floor(validationResponse.timestamp / 60) * 60;
|
|
@@ -119371,6 +119659,7 @@ Position: ${request.positionId}`
|
|
|
119371
119659
|
validationResponse.timestamp,
|
|
119372
119660
|
signatureHexMint
|
|
119373
119661
|
]);
|
|
119662
|
+
await awaitSafeSubmissionWindow(Number(validationResponse.timestamp));
|
|
119374
119663
|
const fromAddress = await signer.getAddress();
|
|
119375
119664
|
const estimatedGas = await estimateContractCallGasWithMargin(
|
|
119376
119665
|
signerProvider,
|
|
@@ -119429,6 +119718,7 @@ Position: ${request.positionId}`
|
|
|
119429
119718
|
"0x131d9a21": "QuantumExpired()",
|
|
119430
119719
|
"0x52ce5d58": "QuantumAlreadyUsed()",
|
|
119431
119720
|
"0x137f3b70": "InDeadZone()",
|
|
119721
|
+
"0xbe4b82c1": "DeadZoneViolation()",
|
|
119432
119722
|
"0x3e76a3c9": "QuantumOutsideWindow()",
|
|
119433
119723
|
"0x62278171": "InvalidValidatorSignature()",
|
|
119434
119724
|
"0xb9d419a7": "DebtUpdateVerificationFailed()",
|
|
@@ -119608,6 +119898,7 @@ Error data: ${errorData || "none"}`
|
|
|
119608
119898
|
"0x131d9a21": "QuantumExpired() - Signature quantum window has closed",
|
|
119609
119899
|
"0x52ce5d58": "QuantumAlreadyUsed() - This quantum was already used for this position",
|
|
119610
119900
|
"0x137f3b70": "InDeadZone() - Timestamp in dead zone (near quantum boundary)",
|
|
119901
|
+
"0xbe4b82c1": "DeadZoneViolation() - Non-current-quantum signature mined in the last 8s of the current quantum",
|
|
119611
119902
|
"0x3e76a3c9": "QuantumOutsideWindow() - Timestamp not in past/current/next quantum window"
|
|
119612
119903
|
};
|
|
119613
119904
|
const errorName = knownErrors[selector] || `Unknown error ${selector}`;
|
|
@@ -120676,6 +120967,7 @@ Error data: ${errorData || "none"}`
|
|
|
120676
120967
|
);
|
|
120677
120968
|
}
|
|
120678
120969
|
const positionManager = positionManagerResult.value;
|
|
120970
|
+
await awaitSafeSubmissionWindow(Number(quantumTimestamp));
|
|
120679
120971
|
const tx = await positionManager["extendPosition"](
|
|
120680
120972
|
positionIdBytes32,
|
|
120681
120973
|
BigInt(_selectedTerm),
|
|
@@ -121108,6 +121400,57 @@ Error data: ${errorData || "none"}`
|
|
|
121108
121400
|
if (!pauseCheck.ok) {
|
|
121109
121401
|
return { success: false, error: pauseCheck.error };
|
|
121110
121402
|
}
|
|
121403
|
+
const MAX_FULL_RETRIES = 3;
|
|
121404
|
+
for (let fullRetry = 1; fullRetry <= MAX_FULL_RETRIES; fullRetry++) {
|
|
121405
|
+
if (fullRetry > 1 && this.config.debug) {
|
|
121406
|
+
log.info(
|
|
121407
|
+
`\u{1F504} Full payment retry ${fullRetry}/${MAX_FULL_RETRIES} due to quantum-timing failure...`,
|
|
121408
|
+
{}
|
|
121409
|
+
);
|
|
121410
|
+
}
|
|
121411
|
+
const result = await this._makePaymentAttempt(request);
|
|
121412
|
+
if (fullRetry < MAX_FULL_RETRIES && this.isRetryablePaymentQuantumFailure(result)) {
|
|
121413
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
121414
|
+
continue;
|
|
121415
|
+
}
|
|
121416
|
+
return result;
|
|
121417
|
+
}
|
|
121418
|
+
return {
|
|
121419
|
+
success: false,
|
|
121420
|
+
error: "Max retries exceeded for payment operation"
|
|
121421
|
+
};
|
|
121422
|
+
} finally {
|
|
121423
|
+
this.invalidateCachesForPosition(request.positionId);
|
|
121424
|
+
this.releaseWriteLock(request.positionId);
|
|
121425
|
+
}
|
|
121426
|
+
}
|
|
121427
|
+
/**
|
|
121428
|
+
* Whether a failed payment attempt is a quantum-timing failure that a fresh
|
|
121429
|
+
* re-sign can fix (safe to retry), versus a terminal failure.
|
|
121430
|
+
*
|
|
121431
|
+
* Retryable: pre-send simulation quantum errors, or an atomic mined revert
|
|
121432
|
+
* (status 0) — no funds moved and the quantum was not recorded on-chain, so a
|
|
121433
|
+
* fresh signature + resubmit is safe.
|
|
121434
|
+
*
|
|
121435
|
+
* NOT retryable: a confirmation timeout — the original tx may still be pending, so
|
|
121436
|
+
* a resubmit could double-pay. It is surfaced (with its tx hash) instead.
|
|
121437
|
+
*/
|
|
121438
|
+
isRetryablePaymentQuantumFailure(result) {
|
|
121439
|
+
if (result.success || !result.error)
|
|
121440
|
+
return false;
|
|
121441
|
+
const e = result.error;
|
|
121442
|
+
if (e.includes("Transaction timeout"))
|
|
121443
|
+
return false;
|
|
121444
|
+
return e.includes("DeadZoneViolation") || e.includes("QuantumOutsideWindow") || e.includes("QuantumAlreadyUsed") || e.includes("QuantumExpired") || e === "Transaction reverted";
|
|
121445
|
+
}
|
|
121446
|
+
/**
|
|
121447
|
+
* One payment attempt: user auth → Lit Action authorization → dead-zone gate →
|
|
121448
|
+
* pre-send simulation → broadcast → confirmation. Always resolves to a
|
|
121449
|
+
* PartialPaymentResult (never throws to the caller); the makePayment wrapper owns
|
|
121450
|
+
* the write lock, the pause pre-check, and the bounded re-sign retry loop.
|
|
121451
|
+
*/
|
|
121452
|
+
async _makePaymentAttempt(request) {
|
|
121453
|
+
try {
|
|
121111
121454
|
if (this.config.debug) {
|
|
121112
121455
|
log.info(`\u{1F4B3} Making payment...`, {});
|
|
121113
121456
|
log.info(` Request object:`, { request });
|
|
@@ -121368,7 +121711,6 @@ Error data: ${errorData || "none"}`
|
|
|
121368
121711
|
error: `Failed to get PositionManager: ${positionManagerResult.error.message}`
|
|
121369
121712
|
};
|
|
121370
121713
|
}
|
|
121371
|
-
const positionManager = positionManagerResult.value;
|
|
121372
121714
|
if (this.config.debug) {
|
|
121373
121715
|
log.info(
|
|
121374
121716
|
` About to call toBytes32 with: ${request.positionId} (type: ${typeof request.positionId})`
|
|
@@ -121428,9 +121770,6 @@ Error data: ${errorData || "none"}`
|
|
|
121428
121770
|
currentQuantum
|
|
121429
121771
|
});
|
|
121430
121772
|
}
|
|
121431
|
-
if (this.config.debug) {
|
|
121432
|
-
log.info("\u23ED\uFE0F Skipping dead zone check to isolate BigNumber issue", {});
|
|
121433
|
-
}
|
|
121434
121773
|
if (this.config.debug) {
|
|
121435
121774
|
log.info("\u{1F50D} Final timestamp validation:", {
|
|
121436
121775
|
litActionTimestamp: litActionResult.timestamp,
|
|
@@ -121497,108 +121836,100 @@ Error data: ${errorData || "none"}`
|
|
|
121497
121836
|
quantumTimestamp: quantumTimestamp.toString()
|
|
121498
121837
|
});
|
|
121499
121838
|
}
|
|
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)
|
|
121839
|
+
await awaitSafeSubmissionWindow(Number(quantumTimestamp));
|
|
121840
|
+
const paymentAmountStr = paymentAmountWei.toString();
|
|
121841
|
+
const quantumTimestampStr = quantumTimestamp.toString();
|
|
121842
|
+
const btcPriceStr = btcPrice.toString();
|
|
121843
|
+
const paymentContractAddress = this.getContractAddressesOrThrow().positionManager;
|
|
121844
|
+
const paymentSigner = this.getSignerOrThrow();
|
|
121845
|
+
const paymentFrom = await paymentSigner.getAddress();
|
|
121846
|
+
const paymentProvider = contractManager.getProvider();
|
|
121847
|
+
const paymentIface = new Interface([
|
|
121848
|
+
"function makePayment(bytes32 positionId, uint256 paymentAmount, uint256 quantumTimestamp, uint256 btcPrice, bytes calldata paymentValidatorSignature) external returns (bool)"
|
|
121849
|
+
]);
|
|
121850
|
+
const paymentCalldata = paymentIface.encodeFunctionData("makePayment", [
|
|
121851
|
+
positionIdBytes32,
|
|
121852
|
+
paymentAmountStr,
|
|
121853
|
+
quantumTimestampStr,
|
|
121854
|
+
btcPriceStr,
|
|
121855
|
+
signature
|
|
121856
|
+
]);
|
|
121857
|
+
const decodePaymentRevert = (e) => {
|
|
121858
|
+
const raw = e?.data ?? e?.info?.error?.data ?? e?.error?.data?.data ?? e?.error?.data;
|
|
121859
|
+
const data = typeof raw === "string" ? raw : void 0;
|
|
121860
|
+
if (!data || !data.startsWith("0x") || data.length < 10)
|
|
121861
|
+
return null;
|
|
121862
|
+
const selector = data.slice(0, 10);
|
|
121863
|
+
const map3 = {
|
|
121864
|
+
"0xbe4b82c1": "DeadZoneViolation()",
|
|
121865
|
+
"0x137f3b70": "InDeadZone()",
|
|
121866
|
+
"0x52ce5d58": "QuantumAlreadyUsed()",
|
|
121867
|
+
"0x3e76a3c9": "QuantumOutsideWindow()",
|
|
121868
|
+
"0x131d9a21": "QuantumExpired()",
|
|
121869
|
+
"0x8baa579f": "InvalidSignature()",
|
|
121870
|
+
"0x62278171": "InvalidValidatorSignature()",
|
|
121871
|
+
"0x3ee5aeb5": "OperationNotAuthorized()",
|
|
121872
|
+
"0x48f5c3ed": "Unauthorized()"
|
|
121873
|
+
};
|
|
121874
|
+
return map3[selector] ?? `Unknown error ${selector}`;
|
|
121875
|
+
};
|
|
121876
|
+
const MAX_DEADZONE_RESIMULATIONS = 3;
|
|
121877
|
+
for (let sim = 1; ; sim++) {
|
|
121878
|
+
try {
|
|
121879
|
+
await paymentProvider.call({
|
|
121880
|
+
to: paymentContractAddress,
|
|
121881
|
+
from: paymentFrom,
|
|
121882
|
+
data: paymentCalldata
|
|
121557
121883
|
});
|
|
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)
|
|
121884
|
+
break;
|
|
121885
|
+
} catch (simError) {
|
|
121886
|
+
const decoded = decodePaymentRevert(simError);
|
|
121887
|
+
if (decoded === "DeadZoneViolation()" && sim <= MAX_DEADZONE_RESIMULATIONS) {
|
|
121888
|
+
const nowSec = Math.floor(Date.now() / 1e3);
|
|
121889
|
+
const sigQuantum = Math.floor(Number(quantumTimestamp) / 60) * 60;
|
|
121890
|
+
const realCurrentQuantum = Math.floor(nowSec / 60) * 60;
|
|
121891
|
+
if (sigQuantum === realCurrentQuantum) {
|
|
121892
|
+
if (this.config.debug) {
|
|
121893
|
+
log.info(
|
|
121894
|
+
"\u21AA\uFE0F Simulated DeadZoneViolation is a stale-latest-block artifact (signature is the current quantum) \u2014 proceeding to broadcast",
|
|
121895
|
+
{}
|
|
121896
|
+
);
|
|
121897
|
+
}
|
|
121898
|
+
break;
|
|
121575
121899
|
}
|
|
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
|
-
});
|
|
121900
|
+
const gate = await awaitSafeSubmissionWindow(Number(quantumTimestamp));
|
|
121901
|
+
if (gate.waited) {
|
|
121902
|
+
if (this.config.debug) {
|
|
121903
|
+
log.info(
|
|
121904
|
+
`\u{1F501} Re-simulating makePayment after crossing the quantum boundary (attempt ${sim}/${MAX_DEADZONE_RESIMULATIONS})`,
|
|
121905
|
+
{}
|
|
121906
|
+
);
|
|
121907
|
+
}
|
|
121908
|
+
continue;
|
|
121909
|
+
}
|
|
121910
|
+
}
|
|
121911
|
+
const label = decoded ?? simError?.reason ?? simError?.shortMessage ?? (simError instanceof Error ? simError.message : String(simError));
|
|
121912
|
+
if (this.config.debug) {
|
|
121913
|
+
log.error("\u274C makePayment pre-send simulation reverted", { error: label });
|
|
121914
|
+
}
|
|
121915
|
+
return {
|
|
121916
|
+
success: false,
|
|
121917
|
+
error: `Payment would revert (pre-send simulation): ${label}`,
|
|
121918
|
+
positionId: request.positionId,
|
|
121919
|
+
paymentAmountUCD: request.paymentAmount
|
|
121920
|
+
};
|
|
121600
121921
|
}
|
|
121601
121922
|
}
|
|
121923
|
+
const MAKE_PAYMENT_GAS_CEILING = 500000n;
|
|
121924
|
+
const tx = await sendEip1559Transaction({
|
|
121925
|
+
signer: paymentSigner,
|
|
121926
|
+
to: paymentContractAddress,
|
|
121927
|
+
data: paymentCalldata,
|
|
121928
|
+
gasLimit: MAKE_PAYMENT_GAS_CEILING
|
|
121929
|
+
});
|
|
121930
|
+
if (this.config.debug) {
|
|
121931
|
+
log.info("\u2705 makePayment broadcast", { txHash: tx.hash });
|
|
121932
|
+
}
|
|
121602
121933
|
if (this.config.debug) {
|
|
121603
121934
|
log.info(`\u{1F4E4} Transaction sent: ${tx.hash}`);
|
|
121604
121935
|
log.info("\u23F3 Waiting for transaction confirmation...");
|
|
@@ -121742,9 +122073,6 @@ Error data: ${errorData || "none"}`
|
|
|
121742
122073
|
result.effectiveGasPrice = receipt.effectiveGasPrice?.toString() || receipt.gasPrice?.toString();
|
|
121743
122074
|
}
|
|
121744
122075
|
return result;
|
|
121745
|
-
} finally {
|
|
121746
|
-
this.invalidateCachesForPosition(request.positionId);
|
|
121747
|
-
this.releaseWriteLock(request.positionId);
|
|
121748
122076
|
}
|
|
121749
122077
|
}
|
|
121750
122078
|
/**
|
|
@@ -122306,6 +122634,7 @@ Error data: ${errorData || "none"}`
|
|
|
122306
122634
|
utxoVout: withdrawalParams.utxoVout
|
|
122307
122635
|
});
|
|
122308
122636
|
}
|
|
122637
|
+
await awaitSafeSubmissionWindow(Number(withdrawalParams.quantumTimestamp));
|
|
122309
122638
|
let tx;
|
|
122310
122639
|
try {
|
|
122311
122640
|
tx = await positionManagerContract["withdrawBTC"](
|