@gvnrdao/dh-lit-ops 0.0.54 → 0.0.61
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/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/interfaces/chunks/authentication.d.ts +0 -1
- package/dist/interfaces/chunks/authentication.d.ts.map +1 -1
- package/dist/interfaces/chunks/config.d.ts +22 -1
- package/dist/interfaces/chunks/config.d.ts.map +1 -1
- package/dist/interfaces/chunks/config.js +53 -0
- package/dist/interfaces/chunks/config.js.map +1 -1
- package/dist/interfaces/chunks/lit-action-execution.d.ts +0 -2
- package/dist/interfaces/chunks/lit-action-execution.d.ts.map +1 -1
- package/dist/interfaces/chunks/pkp-operations.d.ts +0 -1
- package/dist/interfaces/chunks/pkp-operations.d.ts.map +1 -1
- package/dist/modules/action-executor.module.d.ts.map +1 -1
- package/dist/modules/action-executor.module.js +26 -106
- package/dist/modules/action-executor.module.js.map +1 -1
- package/dist/modules/auth-manager.module.d.ts.map +1 -1
- package/dist/modules/auth-manager.module.js +37 -77
- package/dist/modules/auth-manager.module.js.map +1 -1
- package/dist/modules/capacity-master.module.d.ts +2 -2
- package/dist/modules/capacity-master.module.d.ts.map +1 -1
- package/dist/modules/capacity-master.module.js +29 -42
- package/dist/modules/capacity-master.module.js.map +1 -1
- package/dist/modules/lit-ops.module.d.ts +137 -7
- package/dist/modules/lit-ops.module.d.ts.map +1 -1
- package/dist/modules/lit-ops.module.js +261 -292
- package/dist/modules/lit-ops.module.js.map +1 -1
- package/dist/modules/pkp-macros.module.d.ts +1 -3
- package/dist/modules/pkp-macros.module.d.ts.map +1 -1
- package/dist/modules/pkp-macros.module.js +15 -41
- package/dist/modules/pkp-macros.module.js.map +1 -1
- package/dist/modules/pkp-signer.module.d.ts.map +1 -1
- package/dist/modules/pkp-signer.module.js +2 -1
- package/dist/modules/pkp-signer.module.js.map +1 -1
- package/dist/modules/session-signature-manager.module.d.ts +0 -1
- package/dist/modules/session-signature-manager.module.d.ts.map +1 -1
- package/dist/modules/session-signature-manager.module.js +26 -21
- package/dist/modules/session-signature-manager.module.js.map +1 -1
- package/package.json +2 -2
|
@@ -56,6 +56,38 @@ const session_signature_manager_module_1 = require("./session-signature-manager.
|
|
|
56
56
|
const capacity_master_module_1 = require("./capacity-master.module");
|
|
57
57
|
class LitOps {
|
|
58
58
|
constructor(config) {
|
|
59
|
+
// CRITICAL VALIDATION: Reject datil-test immediately with terrifying error
|
|
60
|
+
if (config.network === "datil-test") {
|
|
61
|
+
throw new Error("\n\n" +
|
|
62
|
+
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" +
|
|
63
|
+
"❌ ❌ ❌ FATAL ERROR: datil-test IS NOT SUPPORTED ❌ ❌ ❌\n" +
|
|
64
|
+
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" +
|
|
65
|
+
"\n" +
|
|
66
|
+
"The 'datil-test' network has been PERMANENTLY REMOVED from this codebase.\n" +
|
|
67
|
+
"\n" +
|
|
68
|
+
"WHY THIS ERROR EXISTS:\n" +
|
|
69
|
+
" • datil-test was unstable and caused production failures\n" +
|
|
70
|
+
" • datil-test is deprecated by LIT Protocol\n" +
|
|
71
|
+
" • Using datil-test was masking real production issues\n" +
|
|
72
|
+
"\n" +
|
|
73
|
+
"WHAT YOU MUST DO:\n" +
|
|
74
|
+
" 1. Change ALL 'datil-test' references to 'datil'\n" +
|
|
75
|
+
" 2. Use capacity credits for testing on datil network\n" +
|
|
76
|
+
" 3. Test with the ACTUAL production network (datil)\n" +
|
|
77
|
+
"\n" +
|
|
78
|
+
"WHERE TO LOOK:\n" +
|
|
79
|
+
" • Configuration files (.env, config files)\n" +
|
|
80
|
+
" • Test files (*.test.ts)\n" +
|
|
81
|
+
" • SDK initialization code\n" +
|
|
82
|
+
" • LitOps/LIT Protocol integration points\n" +
|
|
83
|
+
"\n" +
|
|
84
|
+
"EXAMPLE FIX:\n" +
|
|
85
|
+
" ❌ BAD: network: 'datil-test'\n" +
|
|
86
|
+
" ✅ GOOD: network: 'datil'\n" +
|
|
87
|
+
"\n" +
|
|
88
|
+
"This is NOT negotiable. datil-test support will NEVER return.\n" +
|
|
89
|
+
"━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
|
|
90
|
+
}
|
|
59
91
|
this.config = {
|
|
60
92
|
domain: "diamond-hands.local",
|
|
61
93
|
sessionExpirationMinutes: 30, // Extended from 15 to 30 for longer retry cycles
|
|
@@ -290,8 +322,7 @@ class LitOps {
|
|
|
290
322
|
* Execute a LIT Action from CID
|
|
291
323
|
*/
|
|
292
324
|
async executeActionFromCID(cid, pkpPublicKey, params, signer, pkpTokenId, // Optional PKP token ID for session signature scoping
|
|
293
|
-
pkpEthAddress
|
|
294
|
-
additionalPkpTokenIds // Additional PKP token IDs for multi-PKP operations
|
|
325
|
+
pkpEthAddress // Optional PKP Ethereum address for capacity credit delegation
|
|
295
326
|
) {
|
|
296
327
|
const litClient = await this.clientManager.getClient({
|
|
297
328
|
litNetwork: this.config.network,
|
|
@@ -304,7 +335,6 @@ class LitOps {
|
|
|
304
335
|
signer,
|
|
305
336
|
pkpTokenId, // Pass through pkpTokenId for session signature scoping
|
|
306
337
|
pkpEthAddress, // Pass through pkpEthAddress for capacity delegation
|
|
307
|
-
additionalPkpTokenIds, // Pass through additional PKP token IDs for multi-PKP operations
|
|
308
338
|
};
|
|
309
339
|
return this.actionExecutor.executeAction(request, litClient);
|
|
310
340
|
}
|
|
@@ -605,12 +635,10 @@ class LitOps {
|
|
|
605
635
|
console.log(` - targetPkpTokenId: "${targetPkpTokenId}"`);
|
|
606
636
|
console.log(` - targetPkpTokenId type: ${typeof targetPkpTokenId}`);
|
|
607
637
|
console.log(` - targetPkpTokenId length: ${targetPkpTokenId.length}`);
|
|
608
|
-
console.log(` - targetPkpTokenId startsWith '0x': ${targetPkpTokenId.startsWith(
|
|
638
|
+
console.log(` - targetPkpTokenId startsWith '0x': ${targetPkpTokenId.startsWith("0x")}`);
|
|
609
639
|
console.log(` - expectedCid (WILL BE PASSED TO LIT ACTION): "${expectedCid}"`);
|
|
610
640
|
console.log(` - signerPkp.tokenId: "${signerPkp.tokenId}"`);
|
|
611
641
|
console.log(` - signerPkp.ethAddress: "${signerPkp.ethAddress}"`);
|
|
612
|
-
console.log(` - signerPkp.publicKey: "${signerPkp.publicKey?.substring(0, 50)}..."`);
|
|
613
|
-
console.log(` - signerPkp.publicKey full: "${signerPkp.publicKey}"`);
|
|
614
642
|
if (this.config.debug) {
|
|
615
643
|
console.log("\n🔍 LitOps.validatePKPSecurity");
|
|
616
644
|
console.log(` Target PKP: ${targetPkpTokenId}`);
|
|
@@ -619,49 +647,46 @@ class LitOps {
|
|
|
619
647
|
}
|
|
620
648
|
try {
|
|
621
649
|
// Get the PKP validator CID
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
// Validation: Ensure we're using the correct registry for datil network
|
|
626
|
-
if (isDatil && registry !== dh_lit_actions_1.DH_LIT_ACTIONS_DATIL) {
|
|
627
|
-
throw new Error(`Network mismatch: Expected DH_LIT_ACTIONS_DATIL for datil network, but got different registry`);
|
|
628
|
-
}
|
|
629
|
-
const pkpValidatorCid = registry.pkpValidator.cid;
|
|
630
|
-
// Validation: Ensure datil network uses the correct validator CID (version 2.0.0)
|
|
631
|
-
const EXPECTED_DATIL_VALIDATOR_CID = "QmfQjsJTxpd26tBXh5qobxncBeq2iWCPUNDTfUgVGqLis1";
|
|
632
|
-
if (isDatil && pkpValidatorCid !== EXPECTED_DATIL_VALIDATOR_CID) {
|
|
633
|
-
throw new Error(`Invalid validator CID for datil network: Expected ${EXPECTED_DATIL_VALIDATOR_CID} (version 2.0.0), but got ${pkpValidatorCid}`);
|
|
634
|
-
}
|
|
635
|
-
// Get validator CID in hex format for signature (contract expects this CID in signature)
|
|
636
|
-
const validatorCidHex = (0, dh_lit_actions_1.cidToHex)(pkpValidatorCid);
|
|
650
|
+
const pkpValidatorCid = (this.config.network === "datil"
|
|
651
|
+
? dh_lit_actions_1.DH_LIT_ACTIONS_DATIL
|
|
652
|
+
: dh_lit_actions_1.DH_LIT_ACTIONS_DATIL_TEST).pkpValidator.cid;
|
|
637
653
|
if (this.config.debug) {
|
|
638
|
-
console.log(` Network: ${this.config.network}`);
|
|
639
|
-
console.log(` Registry: ${isDatil ? "DH_LIT_ACTIONS_DATIL" : "DH_LIT_ACTIONS_DATIL_TEST"}`);
|
|
640
654
|
console.log(` PKP Validator CID: ${pkpValidatorCid}`);
|
|
641
|
-
console.log(` Validator Version: ${registry.pkpValidator.version}`);
|
|
642
|
-
console.log(` Validator CID (hex, for signature): ${validatorCidHex}`);
|
|
643
655
|
}
|
|
644
656
|
// Execute PKP Validator LIT Action
|
|
645
|
-
// NOTE:
|
|
646
|
-
//
|
|
647
|
-
//
|
|
648
|
-
//
|
|
657
|
+
// NOTE: Even though the validator PKP is burned/immutable (read-only),
|
|
658
|
+
// we still pass its tokenId so the session signature is scoped to the
|
|
659
|
+
// validator resource. The Lit nodes will simply treat the resource as
|
|
660
|
+
// non-signing, but scoping keeps the session principle of least privilege.
|
|
649
661
|
console.log(`\n🔍 LIT-OPS TRACE: About to call executeActionFromCID with jsParams:`);
|
|
650
662
|
console.log(` - targetPkpTokenId: "${targetPkpTokenId}"`);
|
|
651
663
|
console.log(` - expectedCid: "${expectedCid}"`);
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
664
|
+
let sessionScopedSignerTokenId = signerPkp.tokenId;
|
|
665
|
+
try {
|
|
666
|
+
const normalizedHex = BigInt(signerPkp.tokenId)
|
|
667
|
+
.toString(16)
|
|
668
|
+
.padStart(64, "0");
|
|
669
|
+
sessionScopedSignerTokenId = `0x${normalizedHex}`;
|
|
670
|
+
}
|
|
671
|
+
catch (tokenErr) {
|
|
672
|
+
console.warn("⚠️ Failed to normalize signer PKP tokenId to hex, using raw value", tokenErr);
|
|
673
|
+
}
|
|
674
|
+
// Convert validator CID to hex format for signature message
|
|
675
|
+
// The contract expects the validator's CID in the signature, not the PKP's CID
|
|
676
|
+
const validatorCidHex = (0, dh_lit_actions_1.cidToHex)(pkpValidatorCid);
|
|
677
|
+
if (this.config.debug) {
|
|
678
|
+
console.log(` Validator CID (IPFS): ${pkpValidatorCid}`);
|
|
679
|
+
console.log(` Validator CID (hex): ${validatorCidHex}`);
|
|
680
|
+
console.log(` PKP's expected CID (hex): ${expectedCid}`);
|
|
681
|
+
}
|
|
655
682
|
const litResult = await this.executeActionFromCID(pkpValidatorCid, signerPkp.publicKey, {
|
|
656
683
|
targetPkpTokenId,
|
|
657
|
-
expectedCid, //
|
|
658
|
-
certificationCid: validatorCidHex, // Validator CID for signature
|
|
684
|
+
expectedCid, // PKP's LIT Action CID (for validation check)
|
|
685
|
+
certificationCid: validatorCidHex, // Validator's CID (for signature message)
|
|
659
686
|
message: `PKP validation: ${Date.now()}`,
|
|
660
687
|
// Ensure the LIT Action knows which network (datil vs datil-test)
|
|
661
688
|
network: this.config.network,
|
|
662
|
-
}, signer
|
|
663
|
-
// Intentionally NOT passing signerPkp.tokenId - validator is read-only
|
|
664
|
-
// Intentionally NOT passing pkpEthAddress - match main branch pattern
|
|
689
|
+
}, signer, sessionScopedSignerTokenId, signerPkp.ethAddress // Required for capacity delegation on Datil
|
|
665
690
|
);
|
|
666
691
|
if (this.config.debug) {
|
|
667
692
|
console.log(` LIT Action Success: ${litResult.success}`);
|
|
@@ -710,14 +735,8 @@ class LitOps {
|
|
|
710
735
|
// For signing errors, we skip signature verification (architectural limitation)
|
|
711
736
|
if (isSigningError) {
|
|
712
737
|
signatureValid = true; // Mark as valid since validation succeeded
|
|
713
|
-
// Compute PKP address from public key for consistency
|
|
714
|
-
const cleanPublicKey = signerPkp.publicKey.startsWith("0x")
|
|
715
|
-
? signerPkp.publicKey
|
|
716
|
-
: `0x${signerPkp.publicKey}`;
|
|
717
|
-
pkpAddress = ethers_1.ethers.utils.computeAddress(cleanPublicKey);
|
|
718
738
|
if (this.config.debug) {
|
|
719
739
|
console.log(" ℹ️ Signature verification skipped - burned PKP limitation");
|
|
720
|
-
console.log(` PKP Address: ${pkpAddress}`);
|
|
721
740
|
}
|
|
722
741
|
}
|
|
723
742
|
else if (litResult.signatures &&
|
|
@@ -857,10 +876,9 @@ class LitOps {
|
|
|
857
876
|
}
|
|
858
877
|
const retries = this.config.pkpServiceRetryCount ?? 2;
|
|
859
878
|
const retryDelay = this.config.pkpServiceRetryDelayMs ?? 2000;
|
|
860
|
-
const timeoutMs = this.config.pkpServiceTimeoutMs ??
|
|
879
|
+
const timeoutMs = this.config.pkpServiceTimeoutMs ?? 120000;
|
|
861
880
|
let attempt = 0;
|
|
862
881
|
let lastError = null;
|
|
863
|
-
let rateLimitDetected = false;
|
|
864
882
|
while (attempt <= retries) {
|
|
865
883
|
if (this.config.debug) {
|
|
866
884
|
console.log(` 🌐 Service mode: calling ${this.config.serviceEndpoint}/api/lit/pkp/create-diamond-hands-loan (attempt ${attempt + 1}/${retries + 1})`);
|
|
@@ -876,37 +894,7 @@ class LitOps {
|
|
|
876
894
|
}),
|
|
877
895
|
}, timeoutMs);
|
|
878
896
|
if (!response.ok) {
|
|
879
|
-
|
|
880
|
-
let errorMessage = `Service request failed: ${response.status} ${response.statusText}`;
|
|
881
|
-
// Try to parse error text as JSON to extract error message
|
|
882
|
-
let parsedError = null;
|
|
883
|
-
try {
|
|
884
|
-
parsedError = JSON.parse(errorText);
|
|
885
|
-
if (parsedError.error) {
|
|
886
|
-
errorMessage = `${errorMessage} - ${parsedError.error}`;
|
|
887
|
-
}
|
|
888
|
-
else if (parsedError.message) {
|
|
889
|
-
errorMessage = `${errorMessage} - ${parsedError.message}`;
|
|
890
|
-
}
|
|
891
|
-
else if (errorText && errorText.length > 0) {
|
|
892
|
-
errorMessage = `${errorMessage} - ${errorText}`;
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
catch {
|
|
896
|
-
// Not JSON, use raw text if available
|
|
897
|
-
if (errorText && errorText.length > 0) {
|
|
898
|
-
errorMessage = `${errorMessage} - ${errorText}`;
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
// Check for rate limit errors
|
|
902
|
-
const isRateLimit = response.status === 429 ||
|
|
903
|
-
errorText.toLowerCase().includes('rate_limit') ||
|
|
904
|
-
errorText.toLowerCase().includes('rate limit');
|
|
905
|
-
if (isRateLimit) {
|
|
906
|
-
rateLimitDetected = true;
|
|
907
|
-
errorMessage = `Rate limit exceeded: ${errorText || errorMessage}`;
|
|
908
|
-
}
|
|
909
|
-
throw new Error(errorMessage);
|
|
897
|
+
throw new Error(`Service request failed: ${response.status} ${response.statusText}`);
|
|
910
898
|
}
|
|
911
899
|
const result = (await response.json());
|
|
912
900
|
const duration = Date.now() - startTime;
|
|
@@ -937,21 +925,14 @@ class LitOps {
|
|
|
937
925
|
message.includes("NodeJsTimeoutError") ||
|
|
938
926
|
message.includes("Gateway") ||
|
|
939
927
|
message.includes("502");
|
|
940
|
-
const isRateLimit = rateLimitDetected ||
|
|
941
|
-
message.toLowerCase().includes('rate_limit') ||
|
|
942
|
-
message.toLowerCase().includes('rate limit');
|
|
943
928
|
if (this.config.debug) {
|
|
944
|
-
console.error(`❌ Service request failed on attempt ${attempt + 1}
|
|
929
|
+
console.error(`❌ Service request failed on attempt ${attempt + 1}/$${retries + 1}:\n Message: ${message}`);
|
|
945
930
|
}
|
|
946
|
-
|
|
947
|
-
if (attempt < retries && (isTimeout || isRateLimit)) {
|
|
948
|
-
const backoffDelay = isRateLimit
|
|
949
|
-
? Math.min(retryDelay * Math.pow(3, attempt), 60000) // Exponential backoff: 2s, 6s, 18s, max 60s
|
|
950
|
-
: retryDelay;
|
|
931
|
+
if (attempt < retries && isTimeout) {
|
|
951
932
|
if (this.config.debug) {
|
|
952
|
-
console.log(` Retrying after ${
|
|
933
|
+
console.log(` Retrying after ${retryDelay}ms due to transient error...`);
|
|
953
934
|
}
|
|
954
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
935
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
955
936
|
attempt++;
|
|
956
937
|
continue;
|
|
957
938
|
}
|
|
@@ -1045,138 +1026,13 @@ class LitOps {
|
|
|
1045
1026
|
console.log(` ℹ️ Continuing to validation anyway - may fail if propagation incomplete`);
|
|
1046
1027
|
}
|
|
1047
1028
|
}
|
|
1048
|
-
//
|
|
1049
|
-
// This avoids racing propagation by keying off confirmed blocks
|
|
1050
|
-
try {
|
|
1051
|
-
const ethers5 = await Promise.resolve().then(() => __importStar(require("ethers")));
|
|
1052
|
-
const rpcUrl = this.config.network === "datil"
|
|
1053
|
-
? "https://yellowstone-rpc.litprotocol.com"
|
|
1054
|
-
: "https://yellowstone-rpc.litprotocol.com"; // Same for both currently
|
|
1055
|
-
const mintTxHash = pkpData.mintTransactionHash;
|
|
1056
|
-
const confirmationsTarget = this.config.yellowstoneConfirmations ?? 2; // Reduced from 3 to 2 to reduce polling
|
|
1057
|
-
const receiptPollMs = this.config.yellowstoneReceiptPollMs ?? 10000; // Increased from 5s to 10s to reduce rate limit pressure
|
|
1058
|
-
const receiptTimeoutMs = this.config.yellowstoneReceiptTimeoutMs ?? 180000; // 2 minutes
|
|
1059
|
-
if (this.config.debug) {
|
|
1060
|
-
console.log("\n ⏳ Waiting for PKP mint transaction receipt and confirmations...");
|
|
1061
|
-
console.log(` - mintTxHash: ${mintTxHash}`);
|
|
1062
|
-
console.log(` - confirmationsTarget: ${confirmationsTarget}`);
|
|
1063
|
-
console.log(` - poll interval: ${receiptPollMs}ms, timeout: ${receiptTimeoutMs}ms`);
|
|
1064
|
-
}
|
|
1065
|
-
const startedAt = Date.now();
|
|
1066
|
-
let receipt = null;
|
|
1067
|
-
// Poll for receipt
|
|
1068
|
-
while (Date.now() - startedAt < receiptTimeoutMs) {
|
|
1069
|
-
const receiptPayload = {
|
|
1070
|
-
method: "eth_getTransactionReceipt",
|
|
1071
|
-
params: [mintTxHash],
|
|
1072
|
-
id: 1,
|
|
1073
|
-
jsonrpc: "2.0",
|
|
1074
|
-
};
|
|
1075
|
-
const resp = await fetch(rpcUrl, {
|
|
1076
|
-
method: "POST",
|
|
1077
|
-
headers: { "Content-Type": "application/json" },
|
|
1078
|
-
body: JSON.stringify(receiptPayload),
|
|
1079
|
-
});
|
|
1080
|
-
const json = (await resp.json());
|
|
1081
|
-
if (json && json.result) {
|
|
1082
|
-
receipt = json.result;
|
|
1083
|
-
break;
|
|
1084
|
-
}
|
|
1085
|
-
await new Promise((r) => setTimeout(r, receiptPollMs));
|
|
1086
|
-
}
|
|
1087
|
-
if (!receipt) {
|
|
1088
|
-
if (this.config.debug) {
|
|
1089
|
-
console.log(" ⚠️ Mint receipt not found within timeout; continuing optimistically");
|
|
1090
|
-
}
|
|
1091
|
-
}
|
|
1092
|
-
else {
|
|
1093
|
-
// Wait for confirmations
|
|
1094
|
-
const mintedAtBlock = ethers5.BigNumber.from(receipt.blockNumber).toNumber();
|
|
1095
|
-
if (this.config.debug) {
|
|
1096
|
-
console.log(` ✅ Mint receipt found at block ${mintedAtBlock}`);
|
|
1097
|
-
}
|
|
1098
|
-
let currentBlock = mintedAtBlock;
|
|
1099
|
-
while (currentBlock < mintedAtBlock + confirmationsTarget) {
|
|
1100
|
-
const blockNumPayload = { method: "eth_blockNumber", params: [], id: 1, jsonrpc: "2.0" };
|
|
1101
|
-
const bResp = await fetch(rpcUrl, {
|
|
1102
|
-
method: "POST",
|
|
1103
|
-
headers: { "Content-Type": "application/json" },
|
|
1104
|
-
body: JSON.stringify(blockNumPayload),
|
|
1105
|
-
});
|
|
1106
|
-
const bJson = (await bResp.json());
|
|
1107
|
-
if (bJson && bJson.result) {
|
|
1108
|
-
currentBlock = ethers5.BigNumber.from(bJson.result).toNumber();
|
|
1109
|
-
if (this.config.debug) {
|
|
1110
|
-
console.log(` ⛓️ Yellowstone block: ${currentBlock} (target >= ${mintedAtBlock + confirmationsTarget})`);
|
|
1111
|
-
}
|
|
1112
|
-
if (currentBlock >= mintedAtBlock + confirmationsTarget) {
|
|
1113
|
-
break;
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
// Use same polling interval as receipt polling (10s) to reduce rate limit pressure
|
|
1117
|
-
await new Promise((r) => setTimeout(r, receiptPollMs));
|
|
1118
|
-
}
|
|
1119
|
-
if (this.config.debug) {
|
|
1120
|
-
console.log(" ✅ Required confirmations reached; proceeding to existence check");
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
}
|
|
1124
|
-
catch (confirmWaitError) {
|
|
1125
|
-
if (this.config.debug) {
|
|
1126
|
-
console.log(" ⚠️ Error during receipt/confirmation wait:", confirmWaitError);
|
|
1127
|
-
console.log(" Continuing with existence check regardless");
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
// Step 1.75: Verify PKP existence using ownerOf() (more reliable than exists())
|
|
1029
|
+
// Additional delay after burn verification for network consensus
|
|
1131
1030
|
if (this.config.debug) {
|
|
1132
|
-
console.log("\n
|
|
1133
|
-
}
|
|
1134
|
-
try {
|
|
1135
|
-
const ethers5 = await Promise.resolve().then(() => __importStar(require("ethers")));
|
|
1136
|
-
const pkpTokenIdBN = ethers5.BigNumber.from(pkpData.tokenId);
|
|
1137
|
-
const ownerOfCalldata = ethers5.utils.concat([
|
|
1138
|
-
ethers5.utils.id("ownerOf(uint256)").substring(0, 10),
|
|
1139
|
-
ethers5.utils.defaultAbiCoder.encode(["uint256"], [pkpTokenIdBN]),
|
|
1140
|
-
]);
|
|
1141
|
-
const rpcUrl = this.config.network === "datil"
|
|
1142
|
-
? "https://yellowstone-rpc.litprotocol.com"
|
|
1143
|
-
: "https://yellowstone-rpc.litprotocol.com";
|
|
1144
|
-
const pkpNftAddress = process.env.LIT_PKP_NFT_ADDRESS && process.env.LIT_PKP_NFT_ADDRESS.trim() !== ""
|
|
1145
|
-
? process.env.LIT_PKP_NFT_ADDRESS
|
|
1146
|
-
: (this.config.network === "datil"
|
|
1147
|
-
? dh_lit_actions_1.SEPOLIA_DEPLOYMENT.litProtocol?.pkpNftContract
|
|
1148
|
-
: dh_lit_actions_1.LOCALHOST_DEPLOYMENT.litProtocol?.pkpNftContract);
|
|
1149
|
-
const ownerRpcPayload = {
|
|
1150
|
-
method: "eth_call",
|
|
1151
|
-
params: [
|
|
1152
|
-
{
|
|
1153
|
-
to: pkpNftAddress,
|
|
1154
|
-
data: ethers5.utils.hexlify(ownerOfCalldata),
|
|
1155
|
-
},
|
|
1156
|
-
"latest",
|
|
1157
|
-
],
|
|
1158
|
-
id: 1,
|
|
1159
|
-
jsonrpc: "2.0",
|
|
1160
|
-
};
|
|
1161
|
-
const ownerResponse = await fetch(rpcUrl, {
|
|
1162
|
-
method: "POST",
|
|
1163
|
-
headers: { "Content-Type": "application/json" },
|
|
1164
|
-
body: JSON.stringify(ownerRpcPayload),
|
|
1165
|
-
});
|
|
1166
|
-
const ownerResult = (await ownerResponse.json());
|
|
1167
|
-
if (ownerResult.error || !ownerResult.result || ownerResult.result === '0x') {
|
|
1168
|
-
throw new Error(`ownerOf() failed or returned empty (likely propagation): ${ownerResult.error?.message || ownerResult.error || 'empty result'}`);
|
|
1169
|
-
}
|
|
1170
|
-
const owner = ethers5.utils.defaultAbiCoder.decode(["address"], ownerResult.result)[0];
|
|
1171
|
-
if (this.config.debug) {
|
|
1172
|
-
console.log(` ✅ ownerOf() returned: ${owner}`);
|
|
1173
|
-
}
|
|
1031
|
+
console.log("\n ⏳ Additional delay for network consensus (10 seconds)...");
|
|
1174
1032
|
}
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
}
|
|
1179
|
-
// Do not hard-fail here; proceed to validator with retry logic
|
|
1033
|
+
await new Promise((resolve) => setTimeout(resolve, 10000));
|
|
1034
|
+
if (this.config.debug) {
|
|
1035
|
+
console.log(` ✅ Network propagation and consensus complete`);
|
|
1180
1036
|
}
|
|
1181
1037
|
// Step 2: Validate PKP security using pkp-validator LIT Action
|
|
1182
1038
|
const step2Start = Date.now();
|
|
@@ -1202,64 +1058,24 @@ class LitOps {
|
|
|
1202
1058
|
// }
|
|
1203
1059
|
// Use production deployments
|
|
1204
1060
|
validatorPkp = dh_lit_actions_1.DATIL_DEPLOYMENTS.pkpValidator.pkp;
|
|
1205
|
-
// Log validator PKP data for debugging
|
|
1206
|
-
console.log(`🔍 LIT-OPS TRACE: Validator PKP Source Check:`);
|
|
1207
|
-
console.log(` - DATIL_DEPLOYMENTS.pkpValidator.pkp exists:`, !!validatorPkp);
|
|
1208
|
-
console.log(` - DATIL_DEPLOYMENTS.pkpValidator.cid:`, dh_lit_actions_1.DATIL_DEPLOYMENTS.pkpValidator.cid);
|
|
1209
|
-
if (validatorPkp) {
|
|
1210
|
-
console.log(` - validatorPkp.ethAddress:`, validatorPkp.ethAddress);
|
|
1211
|
-
console.log(` - validatorPkp.publicKey:`, validatorPkp.publicKey?.substring(0, 50) + '...');
|
|
1212
|
-
console.log(` - validatorPkp.tokenId:`, validatorPkp.tokenId);
|
|
1213
|
-
}
|
|
1214
|
-
else {
|
|
1215
|
-
console.log(` - DATIL_DEPLOYMENTS.pkpValidator keys:`, Object.keys(dh_lit_actions_1.DATIL_DEPLOYMENTS.pkpValidator));
|
|
1216
|
-
}
|
|
1217
1061
|
if (this.config.debug) {
|
|
1218
1062
|
console.log(" Using production validator PKP", validatorPkp);
|
|
1219
1063
|
}
|
|
1220
1064
|
if (!validatorPkp) {
|
|
1221
1065
|
throw new Error("PKP validator PKP not found in dh-lit-actions package");
|
|
1222
1066
|
}
|
|
1223
|
-
//
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
// They do NOT have the validator CID - that's only for the centralized validator PKP
|
|
1229
|
-
// We validate that the loan PKP has the expected authorization dummy CID
|
|
1230
|
-
const authorizationCid = cids[0]; // First CID in array (authorization dummy)
|
|
1231
|
-
if (!authorizationCid) {
|
|
1232
|
-
throw new Error("Authorization CID not found in cids array");
|
|
1233
|
-
}
|
|
1234
|
-
console.log(`🔍 LIT-OPS TRACE: authorizationCid (first in array) = "${authorizationCid}"`);
|
|
1235
|
-
console.log(`🔍 LIT-OPS TRACE: Authorized actions cids array:`, cids);
|
|
1236
|
-
const litActionCidHex = (0, dh_lit_actions_1.cidToHex)(authorizationCid);
|
|
1067
|
+
// Convert IPFS CID to hex format for validation (using first CID)
|
|
1068
|
+
const firstCid = cids[0];
|
|
1069
|
+
console.log(`🔍 LIT-OPS TRACE: firstCid (cids[0]) = "${firstCid}"`);
|
|
1070
|
+
console.log(`🔍 LIT-OPS TRACE: All cids array:`, cids);
|
|
1071
|
+
const litActionCidHex = (0, dh_lit_actions_1.cidToHex)(firstCid);
|
|
1237
1072
|
console.log(`🔍 LIT-OPS TRACE: litActionCidHex after cidToHex() = "${litActionCidHex}"`);
|
|
1238
1073
|
if (this.config.debug) {
|
|
1239
|
-
console.log(` Converting CID: ${
|
|
1074
|
+
console.log(` Converting CID: ${firstCid} → ${litActionCidHex}`);
|
|
1240
1075
|
}
|
|
1241
|
-
// CERTIFICATION SIGNATURE: Get validator CID for on-chain contract signature
|
|
1242
|
-
// The on-chain contract expects the validator PKP to sign with the VALIDATOR CID
|
|
1243
|
-
// NOT the authorization CID! This is the CID registered in cidForVersion mapping.
|
|
1244
|
-
const validatorCid = (this.config.network === "datil"
|
|
1245
|
-
? dh_lit_actions_1.DH_LIT_ACTIONS_DATIL
|
|
1246
|
-
: dh_lit_actions_1.DH_LIT_ACTIONS_DATIL_TEST).pkpValidator.cid;
|
|
1247
|
-
const validatorCidHex = (0, dh_lit_actions_1.cidToHex)(validatorCid);
|
|
1248
|
-
console.log(`🔍 LIT-OPS TRACE: validatorCid (for signature) = "${validatorCid}"`);
|
|
1249
|
-
console.log(`🔍 LIT-OPS TRACE: validatorCidHex (for signature) = "${validatorCidHex}"`);
|
|
1250
|
-
if (this.config.debug) {
|
|
1251
|
-
console.log(` Validator CID for signature: ${validatorCid} → ${validatorCidHex}`);
|
|
1252
|
-
}
|
|
1253
|
-
// Wait for PKP to propagate on the network before validation
|
|
1254
|
-
// This helps avoid "execution reverted" errors when checking PKP existence
|
|
1255
|
-
if (this.config.debug) {
|
|
1256
|
-
console.log("\n ⏳ Waiting 5 seconds for PKP network propagation before validation...");
|
|
1257
|
-
}
|
|
1258
|
-
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
1259
1076
|
// Attempt validation with retry logic for network propagation issues
|
|
1260
1077
|
let validationResult;
|
|
1261
|
-
const maxValidationRetries =
|
|
1262
|
-
const retryDelays = [2000, 4000, 8000, 16000]; // Exponential backoff: 2s, 4s, 8s, 16s
|
|
1078
|
+
const maxValidationRetries = 2;
|
|
1263
1079
|
let lastValidationError = null;
|
|
1264
1080
|
for (let attempt = 1; attempt <= maxValidationRetries; attempt++) {
|
|
1265
1081
|
try {
|
|
@@ -1283,11 +1099,11 @@ class LitOps {
|
|
|
1283
1099
|
}
|
|
1284
1100
|
// Validation returned but marked as unsuccessful
|
|
1285
1101
|
lastValidationError = new Error(`PKP validation failed: ${validationResult.error || "Unknown validation error"}`);
|
|
1286
|
-
// If not the last attempt, wait before retrying
|
|
1102
|
+
// If not the last attempt, wait before retrying
|
|
1287
1103
|
if (attempt < maxValidationRetries) {
|
|
1288
|
-
const retryDelay =
|
|
1104
|
+
const retryDelay = 10000; // 10 seconds between validation retries
|
|
1289
1105
|
if (this.config.debug) {
|
|
1290
|
-
console.log(` ⏳
|
|
1106
|
+
console.log(` ⏳ Waiting ${retryDelay}ms before retry...`);
|
|
1291
1107
|
}
|
|
1292
1108
|
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
1293
1109
|
}
|
|
@@ -1307,11 +1123,11 @@ class LitOps {
|
|
|
1307
1123
|
console.log(` ℹ️ This appears to be a network propagation issue`);
|
|
1308
1124
|
}
|
|
1309
1125
|
}
|
|
1310
|
-
// If this is a propagation error and not the last attempt, retry
|
|
1126
|
+
// If this is a propagation error and not the last attempt, retry
|
|
1311
1127
|
if (isPropagationError && attempt < maxValidationRetries) {
|
|
1312
|
-
const retryDelay =
|
|
1128
|
+
const retryDelay = 15000; // 15 seconds for propagation issues
|
|
1313
1129
|
if (this.config.debug) {
|
|
1314
|
-
console.log(` ⏳
|
|
1130
|
+
console.log(` ⏳ Waiting ${retryDelay}ms for network propagation before retry...`);
|
|
1315
1131
|
}
|
|
1316
1132
|
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
1317
1133
|
continue;
|
|
@@ -1481,7 +1297,7 @@ class LitOps {
|
|
|
1481
1297
|
console.log(" Has clientManager:", !!this.clientManager);
|
|
1482
1298
|
console.log(" clientManager type:", typeof this.clientManager);
|
|
1483
1299
|
if (this.clientManager) {
|
|
1484
|
-
console.log(" clientManager keys:", Object.keys(this.clientManager).join(
|
|
1300
|
+
console.log(" clientManager keys:", Object.keys(this.clientManager).join(", "));
|
|
1485
1301
|
console.log(" Has getClient:", typeof this.clientManager.getClient);
|
|
1486
1302
|
}
|
|
1487
1303
|
}
|
|
@@ -1498,7 +1314,7 @@ class LitOps {
|
|
|
1498
1314
|
if (this.config.debug) {
|
|
1499
1315
|
console.log("🌐 Requesting mint authorization via service:", url);
|
|
1500
1316
|
console.log(" Position ID:", request.authMessage.positionId);
|
|
1501
|
-
console.log(" Amount:", request.authMessage.
|
|
1317
|
+
console.log(" Amount:", request.authMessage.amount);
|
|
1502
1318
|
}
|
|
1503
1319
|
try {
|
|
1504
1320
|
const response = await fetch(url, {
|
|
@@ -1509,6 +1325,8 @@ class LitOps {
|
|
|
1509
1325
|
body: JSON.stringify({
|
|
1510
1326
|
authMessage: request.authMessage,
|
|
1511
1327
|
userSignature: request.userSignature,
|
|
1328
|
+
customRpcUrl: request.customRpcUrl,
|
|
1329
|
+
customBitcoinRpcUrl: request.customBitcoinRpcUrl,
|
|
1512
1330
|
}),
|
|
1513
1331
|
});
|
|
1514
1332
|
if (!response.ok) {
|
|
@@ -1571,46 +1389,77 @@ class LitOps {
|
|
|
1571
1389
|
console.log(" Network:", this.config.network);
|
|
1572
1390
|
console.log(" CID:", litActionInfo.cid);
|
|
1573
1391
|
console.log(" Position:", request.authMessage.positionId);
|
|
1574
|
-
console.log(" Amount:", request.authMessage.
|
|
1575
|
-
console.log("
|
|
1392
|
+
console.log(" Amount:", request.authMessage.amount);
|
|
1393
|
+
console.log(" Timestamp:", request.authMessage.timestamp);
|
|
1576
1394
|
}
|
|
1577
1395
|
// Get LIT client for execution
|
|
1578
1396
|
const litClient = await this.clientManager.getClient({
|
|
1579
1397
|
litNetwork: this.config.network,
|
|
1580
1398
|
debug: this.config.debug,
|
|
1581
1399
|
});
|
|
1582
|
-
// Determine chain from chainId in authMessage
|
|
1400
|
+
// Determine chain and Bitcoin provider from chainId in authMessage
|
|
1583
1401
|
let chain;
|
|
1402
|
+
let bitcoinProviderUrl;
|
|
1584
1403
|
switch (request.authMessage.chainId) {
|
|
1585
|
-
case 1:
|
|
1404
|
+
case 1: // Ethereum mainnet
|
|
1586
1405
|
chain = "ethereum";
|
|
1406
|
+
bitcoinProviderUrl =
|
|
1407
|
+
process.env.BITCOIN_PROVIDER_URL || "https://mempool.space/api";
|
|
1587
1408
|
break;
|
|
1588
|
-
case 11155111:
|
|
1409
|
+
case 11155111: // Sepolia testnet
|
|
1589
1410
|
chain = "sepolia";
|
|
1411
|
+
bitcoinProviderUrl =
|
|
1412
|
+
process.env.BITCOIN_PROVIDER_URL ||
|
|
1413
|
+
"https://diamond-hands-btc-faucet-6b39a1072059.herokuapp.com/api";
|
|
1590
1414
|
break;
|
|
1591
|
-
case
|
|
1592
|
-
|
|
1415
|
+
case 1337: // Hardhat local testnet (actual deployment chainId)
|
|
1416
|
+
case 31337: // Hardhat local testnet (standard default)
|
|
1417
|
+
chain = "hardhat"; // Use hardhat identifier for local testing
|
|
1418
|
+
bitcoinProviderUrl =
|
|
1419
|
+
process.env.BITCOIN_PROVIDER_URL || "http://127.0.0.1:18443"; // Local Bitcoin regtest
|
|
1593
1420
|
break;
|
|
1594
1421
|
default:
|
|
1595
1422
|
throw new Error(`Unsupported chainId: ${request.authMessage.chainId}`);
|
|
1596
1423
|
}
|
|
1597
|
-
//
|
|
1598
|
-
|
|
1424
|
+
// Override with custom Bitcoin RPC URL if provided (for local development)
|
|
1425
|
+
if (request.customBitcoinRpcUrl) {
|
|
1426
|
+
bitcoinProviderUrl = request.customBitcoinRpcUrl;
|
|
1427
|
+
if (this.config.debug) {
|
|
1428
|
+
console.log(" Custom Bitcoin RPC URL:", request.customBitcoinRpcUrl);
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1599
1431
|
// Execute LIT Action
|
|
1600
|
-
// authMessage already contains
|
|
1432
|
+
// authMessage already contains timestamp calculated by SDK
|
|
1601
1433
|
// lit-ops just forwards - no business logic
|
|
1434
|
+
const litActionParams = {
|
|
1435
|
+
chain,
|
|
1436
|
+
bitcoinProviderUrl,
|
|
1437
|
+
auth: {
|
|
1438
|
+
positionId: request.authMessage.positionId,
|
|
1439
|
+
timestamp: request.authMessage.timestamp,
|
|
1440
|
+
chainId: request.authMessage.chainId,
|
|
1441
|
+
amount: request.authMessage.amount,
|
|
1442
|
+
action: request.authMessage.action,
|
|
1443
|
+
signature: request.userSignature,
|
|
1444
|
+
mode: request.authMessage.mode,
|
|
1445
|
+
...(request.authMessage.contracts && {
|
|
1446
|
+
contracts: request.authMessage.contracts,
|
|
1447
|
+
}),
|
|
1448
|
+
},
|
|
1449
|
+
amount: request.authMessage.amount,
|
|
1450
|
+
};
|
|
1451
|
+
// Add custom RPC URL for local development (ngrok tunnels)
|
|
1452
|
+
if (request.customRpcUrl) {
|
|
1453
|
+
litActionParams.customRpcUrl = request.customRpcUrl;
|
|
1454
|
+
if (this.config.debug) {
|
|
1455
|
+
console.log(" Custom RPC URL:", request.customRpcUrl);
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
// Execute LIT Action (single attempt - retry logic is in SDK layer)
|
|
1602
1459
|
const result = await this.actionExecutor.executeAction({
|
|
1603
1460
|
cid: litActionInfo.cid,
|
|
1604
1461
|
pkpPublicKey: litActionInfo.pkp.publicKey,
|
|
1605
|
-
params:
|
|
1606
|
-
chain,
|
|
1607
|
-
bitcoinProviderUrl,
|
|
1608
|
-
auth: {
|
|
1609
|
-
message: request.authMessage,
|
|
1610
|
-
signature: request.userSignature,
|
|
1611
|
-
},
|
|
1612
|
-
amount: request.authMessage.requestedAmount,
|
|
1613
|
-
},
|
|
1462
|
+
params: litActionParams,
|
|
1614
1463
|
signer: this.config.signer,
|
|
1615
1464
|
}, litClient);
|
|
1616
1465
|
if (this.config.debug) {
|
|
@@ -1624,7 +1473,7 @@ class LitOps {
|
|
|
1624
1473
|
}
|
|
1625
1474
|
// Parse response if it's a string (LIT Actions return JSON as string)
|
|
1626
1475
|
let responseData = result.response;
|
|
1627
|
-
if (typeof result.response ===
|
|
1476
|
+
if (typeof result.response === "string") {
|
|
1628
1477
|
try {
|
|
1629
1478
|
responseData = JSON.parse(result.response);
|
|
1630
1479
|
if (this.config.debug) {
|
|
@@ -1829,6 +1678,126 @@ class LitOps {
|
|
|
1829
1678
|
results,
|
|
1830
1679
|
};
|
|
1831
1680
|
}
|
|
1681
|
+
/**
|
|
1682
|
+
* NOLA (No LIT Action) - Vault Snapshot
|
|
1683
|
+
*
|
|
1684
|
+
* Cost-optimized data access for position health metrics.
|
|
1685
|
+
* Executes vault-snapshot logic in Node.js without paying for LIT Action execution.
|
|
1686
|
+
*
|
|
1687
|
+
* Modes:
|
|
1688
|
+
* - Standalone: Calls executeVaultSnapshot directly with provided RPC URLs
|
|
1689
|
+
* - Service: Sends request to lit-ops-server which provides credentials
|
|
1690
|
+
*
|
|
1691
|
+
* @param params - Position and network configuration
|
|
1692
|
+
* @returns Complete VaultSnapshot with position health data
|
|
1693
|
+
/
|
|
1694
|
+
async getVaultSnapshot(params: {
|
|
1695
|
+
positionId: string;
|
|
1696
|
+
network: "sepolia" | "ethereum" | "localhost";
|
|
1697
|
+
// Standalone mode requires these:
|
|
1698
|
+
contractAddress?: string;
|
|
1699
|
+
termManagerAddress?: string;
|
|
1700
|
+
loanOpsManagerAddress?: string;
|
|
1701
|
+
chainId?: number;
|
|
1702
|
+
rpcUrl?: string;
|
|
1703
|
+
bitcoinProviderUrl?: string;
|
|
1704
|
+
minConfirmations?: number;
|
|
1705
|
+
}) {
|
|
1706
|
+
if (this.config.mode === "standalone") {
|
|
1707
|
+
// Standalone mode: Direct execution with provided credentials
|
|
1708
|
+
if (
|
|
1709
|
+
!params.contractAddress ||
|
|
1710
|
+
!params.rpcUrl ||
|
|
1711
|
+
!params.bitcoinProviderUrl
|
|
1712
|
+
) {
|
|
1713
|
+
throw new Error(
|
|
1714
|
+
"Standalone mode requires: contractAddress, rpcUrl, bitcoinProviderUrl"
|
|
1715
|
+
);
|
|
1716
|
+
}
|
|
1717
|
+
if (!params.termManagerAddress || !params.loanOpsManagerAddress) {
|
|
1718
|
+
throw new Error(
|
|
1719
|
+
"Standalone mode requires: termManagerAddress, loanOpsManagerAddress"
|
|
1720
|
+
);
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
// Import NOLA executor
|
|
1724
|
+
const { executeVaultSnapshot } = await import("@gvnrdao/dh-lit-actions");
|
|
1725
|
+
|
|
1726
|
+
// Execute directly
|
|
1727
|
+
return await executeVaultSnapshot({
|
|
1728
|
+
positionId: params.positionId,
|
|
1729
|
+
contractAddress: params.contractAddress,
|
|
1730
|
+
termManagerAddress: params.termManagerAddress,
|
|
1731
|
+
loanOpsManagerAddress: params.loanOpsManagerAddress,
|
|
1732
|
+
chain: params.network,
|
|
1733
|
+
chainId: params.chainId,
|
|
1734
|
+
rpcUrl: params.rpcUrl,
|
|
1735
|
+
bitcoinProviderUrl: params.bitcoinProviderUrl,
|
|
1736
|
+
minConfirmations: params.minConfirmations || 6,
|
|
1737
|
+
});
|
|
1738
|
+
} else {
|
|
1739
|
+
// Service mode: Call lit-ops-server endpoint
|
|
1740
|
+
if (!this.config.serviceEndpoint) {
|
|
1741
|
+
throw new Error("serviceEndpoint is required for service mode");
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
const response = await fetch(
|
|
1745
|
+
`${this.config.serviceEndpoint}/api/lit/nola/vault-snapshot`,
|
|
1746
|
+
{
|
|
1747
|
+
method: "POST",
|
|
1748
|
+
headers: {
|
|
1749
|
+
"Content-Type": "application/json",
|
|
1750
|
+
},
|
|
1751
|
+
body: JSON.stringify({
|
|
1752
|
+
positionId: params.positionId,
|
|
1753
|
+
network: params.network,
|
|
1754
|
+
}),
|
|
1755
|
+
}
|
|
1756
|
+
);
|
|
1757
|
+
|
|
1758
|
+
if (!response.ok) {
|
|
1759
|
+
const errorText = await response.text();
|
|
1760
|
+
throw new Error(
|
|
1761
|
+
`NOLA service request failed: ${response.status} ${errorText}`
|
|
1762
|
+
);
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
const apiResponse: any = await response.json();
|
|
1766
|
+
|
|
1767
|
+
// Convert string BigInts back to BigInt type
|
|
1768
|
+
const convertStringsToBigInt = (obj: any): any => {
|
|
1769
|
+
if (obj === null || obj === undefined) return obj;
|
|
1770
|
+
|
|
1771
|
+
if (typeof obj === "string") {
|
|
1772
|
+
// Check if string is a valid BigInt representation
|
|
1773
|
+
if (/^\d+$/.test(obj)) {
|
|
1774
|
+
try {
|
|
1775
|
+
return BigInt(obj);
|
|
1776
|
+
} catch {
|
|
1777
|
+
return obj;
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
return obj;
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
if (Array.isArray(obj)) {
|
|
1784
|
+
return obj.map(convertStringsToBigInt);
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
if (typeof obj === "object") {
|
|
1788
|
+
const converted: any = {};
|
|
1789
|
+
for (const key in obj) {
|
|
1790
|
+
converted[key] = convertStringsToBigInt(obj[key]);
|
|
1791
|
+
}
|
|
1792
|
+
return converted;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
return obj;
|
|
1796
|
+
};
|
|
1797
|
+
|
|
1798
|
+
return convertStringsToBigInt(apiResponse.data); // Unwrap and convert
|
|
1799
|
+
}
|
|
1800
|
+
} */
|
|
1832
1801
|
async disconnect() {
|
|
1833
1802
|
// Ensure capacity module timers are cleaned up first
|
|
1834
1803
|
try {
|