@gvnrdao/dh-lit-ops 0.0.55 → 0.0.73
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 +41 -76
- 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 +313 -295
- 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.map +1 -1
- package/dist/modules/session-signature-manager.module.js +26 -20
- 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
|
}
|
|
@@ -448,6 +478,8 @@ class LitOps {
|
|
|
448
478
|
pkpPublicKey,
|
|
449
479
|
params,
|
|
450
480
|
signer,
|
|
481
|
+
// Include pkpTokenId for session signature scoping (required for burned PKPs)
|
|
482
|
+
pkpTokenId: pkpTokenId || params?.pkpTokenId,
|
|
451
483
|
};
|
|
452
484
|
return this.actionExecutor.executeAction(request, litClient);
|
|
453
485
|
}
|
|
@@ -605,12 +637,10 @@ class LitOps {
|
|
|
605
637
|
console.log(` - targetPkpTokenId: "${targetPkpTokenId}"`);
|
|
606
638
|
console.log(` - targetPkpTokenId type: ${typeof targetPkpTokenId}`);
|
|
607
639
|
console.log(` - targetPkpTokenId length: ${targetPkpTokenId.length}`);
|
|
608
|
-
console.log(` - targetPkpTokenId startsWith '0x': ${targetPkpTokenId.startsWith(
|
|
640
|
+
console.log(` - targetPkpTokenId startsWith '0x': ${targetPkpTokenId.startsWith("0x")}`);
|
|
609
641
|
console.log(` - expectedCid (WILL BE PASSED TO LIT ACTION): "${expectedCid}"`);
|
|
610
642
|
console.log(` - signerPkp.tokenId: "${signerPkp.tokenId}"`);
|
|
611
643
|
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
644
|
if (this.config.debug) {
|
|
615
645
|
console.log("\n🔍 LitOps.validatePKPSecurity");
|
|
616
646
|
console.log(` Target PKP: ${targetPkpTokenId}`);
|
|
@@ -619,49 +649,46 @@ class LitOps {
|
|
|
619
649
|
}
|
|
620
650
|
try {
|
|
621
651
|
// 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);
|
|
652
|
+
const pkpValidatorCid = (this.config.network === "datil"
|
|
653
|
+
? dh_lit_actions_1.DH_LIT_ACTIONS_DATIL
|
|
654
|
+
: dh_lit_actions_1.DH_LIT_ACTIONS_DATIL_TEST).pkpValidator.cid;
|
|
637
655
|
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
656
|
console.log(` PKP Validator CID: ${pkpValidatorCid}`);
|
|
641
|
-
console.log(` Validator Version: ${registry.pkpValidator.version}`);
|
|
642
|
-
console.log(` Validator CID (hex, for signature): ${validatorCidHex}`);
|
|
643
657
|
}
|
|
644
658
|
// Execute PKP Validator LIT Action
|
|
645
|
-
// NOTE:
|
|
646
|
-
//
|
|
647
|
-
//
|
|
648
|
-
//
|
|
659
|
+
// NOTE: Even though the validator PKP is burned/immutable (read-only),
|
|
660
|
+
// we still pass its tokenId so the session signature is scoped to the
|
|
661
|
+
// validator resource. The Lit nodes will simply treat the resource as
|
|
662
|
+
// non-signing, but scoping keeps the session principle of least privilege.
|
|
649
663
|
console.log(`\n🔍 LIT-OPS TRACE: About to call executeActionFromCID with jsParams:`);
|
|
650
664
|
console.log(` - targetPkpTokenId: "${targetPkpTokenId}"`);
|
|
651
665
|
console.log(` - expectedCid: "${expectedCid}"`);
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
666
|
+
let sessionScopedSignerTokenId = signerPkp.tokenId;
|
|
667
|
+
try {
|
|
668
|
+
const normalizedHex = BigInt(signerPkp.tokenId)
|
|
669
|
+
.toString(16)
|
|
670
|
+
.padStart(64, "0");
|
|
671
|
+
sessionScopedSignerTokenId = `0x${normalizedHex}`;
|
|
672
|
+
}
|
|
673
|
+
catch (tokenErr) {
|
|
674
|
+
console.warn("⚠️ Failed to normalize signer PKP tokenId to hex, using raw value", tokenErr);
|
|
675
|
+
}
|
|
676
|
+
// Convert validator CID to hex format for signature message
|
|
677
|
+
// The contract expects the validator's CID in the signature, not the PKP's CID
|
|
678
|
+
const validatorCidHex = (0, dh_lit_actions_1.cidToHex)(pkpValidatorCid);
|
|
679
|
+
if (this.config.debug) {
|
|
680
|
+
console.log(` Validator CID (IPFS): ${pkpValidatorCid}`);
|
|
681
|
+
console.log(` Validator CID (hex): ${validatorCidHex}`);
|
|
682
|
+
console.log(` PKP's expected CID (hex): ${expectedCid}`);
|
|
683
|
+
}
|
|
655
684
|
const litResult = await this.executeActionFromCID(pkpValidatorCid, signerPkp.publicKey, {
|
|
656
685
|
targetPkpTokenId,
|
|
657
|
-
expectedCid, //
|
|
658
|
-
certificationCid: validatorCidHex, // Validator CID for signature
|
|
686
|
+
expectedCid, // PKP's LIT Action CID (for validation check)
|
|
687
|
+
certificationCid: validatorCidHex, // Validator's CID (for signature message)
|
|
659
688
|
message: `PKP validation: ${Date.now()}`,
|
|
660
689
|
// Ensure the LIT Action knows which network (datil vs datil-test)
|
|
661
690
|
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
|
|
691
|
+
}, signer, sessionScopedSignerTokenId, signerPkp.ethAddress // Required for capacity delegation on Datil
|
|
665
692
|
);
|
|
666
693
|
if (this.config.debug) {
|
|
667
694
|
console.log(` LIT Action Success: ${litResult.success}`);
|
|
@@ -710,14 +737,8 @@ class LitOps {
|
|
|
710
737
|
// For signing errors, we skip signature verification (architectural limitation)
|
|
711
738
|
if (isSigningError) {
|
|
712
739
|
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
740
|
if (this.config.debug) {
|
|
719
741
|
console.log(" ℹ️ Signature verification skipped - burned PKP limitation");
|
|
720
|
-
console.log(` PKP Address: ${pkpAddress}`);
|
|
721
742
|
}
|
|
722
743
|
}
|
|
723
744
|
else if (litResult.signatures &&
|
|
@@ -857,10 +878,9 @@ class LitOps {
|
|
|
857
878
|
}
|
|
858
879
|
const retries = this.config.pkpServiceRetryCount ?? 2;
|
|
859
880
|
const retryDelay = this.config.pkpServiceRetryDelayMs ?? 2000;
|
|
860
|
-
const timeoutMs = this.config.pkpServiceTimeoutMs ??
|
|
881
|
+
const timeoutMs = this.config.pkpServiceTimeoutMs ?? 120000;
|
|
861
882
|
let attempt = 0;
|
|
862
883
|
let lastError = null;
|
|
863
|
-
let rateLimitDetected = false;
|
|
864
884
|
while (attempt <= retries) {
|
|
865
885
|
if (this.config.debug) {
|
|
866
886
|
console.log(` 🌐 Service mode: calling ${this.config.serviceEndpoint}/api/lit/pkp/create-diamond-hands-loan (attempt ${attempt + 1}/${retries + 1})`);
|
|
@@ -876,37 +896,7 @@ class LitOps {
|
|
|
876
896
|
}),
|
|
877
897
|
}, timeoutMs);
|
|
878
898
|
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);
|
|
899
|
+
throw new Error(`Service request failed: ${response.status} ${response.statusText}`);
|
|
910
900
|
}
|
|
911
901
|
const result = (await response.json());
|
|
912
902
|
const duration = Date.now() - startTime;
|
|
@@ -937,21 +927,14 @@ class LitOps {
|
|
|
937
927
|
message.includes("NodeJsTimeoutError") ||
|
|
938
928
|
message.includes("Gateway") ||
|
|
939
929
|
message.includes("502");
|
|
940
|
-
const isRateLimit = rateLimitDetected ||
|
|
941
|
-
message.toLowerCase().includes('rate_limit') ||
|
|
942
|
-
message.toLowerCase().includes('rate limit');
|
|
943
930
|
if (this.config.debug) {
|
|
944
|
-
console.error(`❌ Service request failed on attempt ${attempt + 1}
|
|
931
|
+
console.error(`❌ Service request failed on attempt ${attempt + 1}/$${retries + 1}:\n Message: ${message}`);
|
|
945
932
|
}
|
|
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;
|
|
933
|
+
if (attempt < retries && isTimeout) {
|
|
951
934
|
if (this.config.debug) {
|
|
952
|
-
console.log(` Retrying after ${
|
|
935
|
+
console.log(` Retrying after ${retryDelay}ms due to transient error...`);
|
|
953
936
|
}
|
|
954
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
937
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
955
938
|
attempt++;
|
|
956
939
|
continue;
|
|
957
940
|
}
|
|
@@ -1045,138 +1028,13 @@ class LitOps {
|
|
|
1045
1028
|
console.log(` ℹ️ Continuing to validation anyway - may fail if propagation incomplete`);
|
|
1046
1029
|
}
|
|
1047
1030
|
}
|
|
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())
|
|
1031
|
+
// Additional delay after burn verification for network consensus
|
|
1131
1032
|
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
|
-
}
|
|
1033
|
+
console.log("\n ⏳ Additional delay for network consensus (10 seconds)...");
|
|
1174
1034
|
}
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
}
|
|
1179
|
-
// Do not hard-fail here; proceed to validator with retry logic
|
|
1035
|
+
await new Promise((resolve) => setTimeout(resolve, 10000));
|
|
1036
|
+
if (this.config.debug) {
|
|
1037
|
+
console.log(` ✅ Network propagation and consensus complete`);
|
|
1180
1038
|
}
|
|
1181
1039
|
// Step 2: Validate PKP security using pkp-validator LIT Action
|
|
1182
1040
|
const step2Start = Date.now();
|
|
@@ -1202,64 +1060,24 @@ class LitOps {
|
|
|
1202
1060
|
// }
|
|
1203
1061
|
// Use production deployments
|
|
1204
1062
|
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
1063
|
if (this.config.debug) {
|
|
1218
1064
|
console.log(" Using production validator PKP", validatorPkp);
|
|
1219
1065
|
}
|
|
1220
1066
|
if (!validatorPkp) {
|
|
1221
1067
|
throw new Error("PKP validator PKP not found in dh-lit-actions package");
|
|
1222
1068
|
}
|
|
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);
|
|
1069
|
+
// Convert IPFS CID to hex format for validation (using first CID)
|
|
1070
|
+
const firstCid = cids[0];
|
|
1071
|
+
console.log(`🔍 LIT-OPS TRACE: firstCid (cids[0]) = "${firstCid}"`);
|
|
1072
|
+
console.log(`🔍 LIT-OPS TRACE: All cids array:`, cids);
|
|
1073
|
+
const litActionCidHex = (0, dh_lit_actions_1.cidToHex)(firstCid);
|
|
1237
1074
|
console.log(`🔍 LIT-OPS TRACE: litActionCidHex after cidToHex() = "${litActionCidHex}"`);
|
|
1238
1075
|
if (this.config.debug) {
|
|
1239
|
-
console.log(` Converting CID: ${
|
|
1240
|
-
}
|
|
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...");
|
|
1076
|
+
console.log(` Converting CID: ${firstCid} → ${litActionCidHex}`);
|
|
1257
1077
|
}
|
|
1258
|
-
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
1259
1078
|
// Attempt validation with retry logic for network propagation issues
|
|
1260
1079
|
let validationResult;
|
|
1261
|
-
const maxValidationRetries =
|
|
1262
|
-
const retryDelays = [2000, 4000, 8000, 16000]; // Exponential backoff: 2s, 4s, 8s, 16s
|
|
1080
|
+
const maxValidationRetries = 2;
|
|
1263
1081
|
let lastValidationError = null;
|
|
1264
1082
|
for (let attempt = 1; attempt <= maxValidationRetries; attempt++) {
|
|
1265
1083
|
try {
|
|
@@ -1283,11 +1101,11 @@ class LitOps {
|
|
|
1283
1101
|
}
|
|
1284
1102
|
// Validation returned but marked as unsuccessful
|
|
1285
1103
|
lastValidationError = new Error(`PKP validation failed: ${validationResult.error || "Unknown validation error"}`);
|
|
1286
|
-
// If not the last attempt, wait before retrying
|
|
1104
|
+
// If not the last attempt, wait before retrying
|
|
1287
1105
|
if (attempt < maxValidationRetries) {
|
|
1288
|
-
const retryDelay =
|
|
1106
|
+
const retryDelay = 10000; // 10 seconds between validation retries
|
|
1289
1107
|
if (this.config.debug) {
|
|
1290
|
-
console.log(` ⏳
|
|
1108
|
+
console.log(` ⏳ Waiting ${retryDelay}ms before retry...`);
|
|
1291
1109
|
}
|
|
1292
1110
|
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
1293
1111
|
}
|
|
@@ -1307,11 +1125,11 @@ class LitOps {
|
|
|
1307
1125
|
console.log(` ℹ️ This appears to be a network propagation issue`);
|
|
1308
1126
|
}
|
|
1309
1127
|
}
|
|
1310
|
-
// If this is a propagation error and not the last attempt, retry
|
|
1128
|
+
// If this is a propagation error and not the last attempt, retry
|
|
1311
1129
|
if (isPropagationError && attempt < maxValidationRetries) {
|
|
1312
|
-
const retryDelay =
|
|
1130
|
+
const retryDelay = 15000; // 15 seconds for propagation issues
|
|
1313
1131
|
if (this.config.debug) {
|
|
1314
|
-
console.log(` ⏳
|
|
1132
|
+
console.log(` ⏳ Waiting ${retryDelay}ms for network propagation before retry...`);
|
|
1315
1133
|
}
|
|
1316
1134
|
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
1317
1135
|
continue;
|
|
@@ -1481,7 +1299,7 @@ class LitOps {
|
|
|
1481
1299
|
console.log(" Has clientManager:", !!this.clientManager);
|
|
1482
1300
|
console.log(" clientManager type:", typeof this.clientManager);
|
|
1483
1301
|
if (this.clientManager) {
|
|
1484
|
-
console.log(" clientManager keys:", Object.keys(this.clientManager).join(
|
|
1302
|
+
console.log(" clientManager keys:", Object.keys(this.clientManager).join(", "));
|
|
1485
1303
|
console.log(" Has getClient:", typeof this.clientManager.getClient);
|
|
1486
1304
|
}
|
|
1487
1305
|
}
|
|
@@ -1498,7 +1316,7 @@ class LitOps {
|
|
|
1498
1316
|
if (this.config.debug) {
|
|
1499
1317
|
console.log("🌐 Requesting mint authorization via service:", url);
|
|
1500
1318
|
console.log(" Position ID:", request.authMessage.positionId);
|
|
1501
|
-
console.log(" Amount:", request.authMessage.
|
|
1319
|
+
console.log(" Amount:", request.authMessage.amount);
|
|
1502
1320
|
}
|
|
1503
1321
|
try {
|
|
1504
1322
|
const response = await fetch(url, {
|
|
@@ -1509,6 +1327,8 @@ class LitOps {
|
|
|
1509
1327
|
body: JSON.stringify({
|
|
1510
1328
|
authMessage: request.authMessage,
|
|
1511
1329
|
userSignature: request.userSignature,
|
|
1330
|
+
customRpcUrl: request.customRpcUrl,
|
|
1331
|
+
customBitcoinRpcUrl: request.customBitcoinRpcUrl,
|
|
1512
1332
|
}),
|
|
1513
1333
|
});
|
|
1514
1334
|
if (!response.ok) {
|
|
@@ -1571,46 +1391,77 @@ class LitOps {
|
|
|
1571
1391
|
console.log(" Network:", this.config.network);
|
|
1572
1392
|
console.log(" CID:", litActionInfo.cid);
|
|
1573
1393
|
console.log(" Position:", request.authMessage.positionId);
|
|
1574
|
-
console.log(" Amount:", request.authMessage.
|
|
1575
|
-
console.log("
|
|
1394
|
+
console.log(" Amount:", request.authMessage.amount);
|
|
1395
|
+
console.log(" Timestamp:", request.authMessage.timestamp);
|
|
1576
1396
|
}
|
|
1577
1397
|
// Get LIT client for execution
|
|
1578
1398
|
const litClient = await this.clientManager.getClient({
|
|
1579
1399
|
litNetwork: this.config.network,
|
|
1580
1400
|
debug: this.config.debug,
|
|
1581
1401
|
});
|
|
1582
|
-
// Determine chain from chainId in authMessage
|
|
1402
|
+
// Determine chain and Bitcoin provider from chainId in authMessage
|
|
1583
1403
|
let chain;
|
|
1404
|
+
let bitcoinProviderUrl;
|
|
1584
1405
|
switch (request.authMessage.chainId) {
|
|
1585
|
-
case 1:
|
|
1406
|
+
case 1: // Ethereum mainnet
|
|
1586
1407
|
chain = "ethereum";
|
|
1408
|
+
bitcoinProviderUrl =
|
|
1409
|
+
process.env.BITCOIN_PROVIDER_URL || "https://mempool.space/api";
|
|
1587
1410
|
break;
|
|
1588
|
-
case 11155111:
|
|
1411
|
+
case 11155111: // Sepolia testnet
|
|
1589
1412
|
chain = "sepolia";
|
|
1413
|
+
bitcoinProviderUrl =
|
|
1414
|
+
process.env.BITCOIN_PROVIDER_URL ||
|
|
1415
|
+
"https://diamond-hands-btc-faucet-6b39a1072059.herokuapp.com/api";
|
|
1590
1416
|
break;
|
|
1591
|
-
case
|
|
1592
|
-
|
|
1417
|
+
case 1337: // Hardhat local testnet (actual deployment chainId)
|
|
1418
|
+
case 31337: // Hardhat local testnet (standard default)
|
|
1419
|
+
chain = "hardhat"; // Use hardhat identifier for local testing
|
|
1420
|
+
bitcoinProviderUrl =
|
|
1421
|
+
process.env.BITCOIN_PROVIDER_URL || "http://127.0.0.1:18443"; // Local Bitcoin regtest
|
|
1593
1422
|
break;
|
|
1594
1423
|
default:
|
|
1595
1424
|
throw new Error(`Unsupported chainId: ${request.authMessage.chainId}`);
|
|
1596
1425
|
}
|
|
1597
|
-
//
|
|
1598
|
-
|
|
1426
|
+
// Override with custom Bitcoin RPC URL if provided (for local development)
|
|
1427
|
+
if (request.customBitcoinRpcUrl) {
|
|
1428
|
+
bitcoinProviderUrl = request.customBitcoinRpcUrl;
|
|
1429
|
+
if (this.config.debug) {
|
|
1430
|
+
console.log(" Custom Bitcoin RPC URL:", request.customBitcoinRpcUrl);
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1599
1433
|
// Execute LIT Action
|
|
1600
|
-
// authMessage already contains
|
|
1434
|
+
// authMessage already contains timestamp calculated by SDK
|
|
1601
1435
|
// lit-ops just forwards - no business logic
|
|
1436
|
+
const litActionParams = {
|
|
1437
|
+
chain,
|
|
1438
|
+
bitcoinProviderUrl,
|
|
1439
|
+
auth: {
|
|
1440
|
+
positionId: request.authMessage.positionId,
|
|
1441
|
+
timestamp: request.authMessage.timestamp,
|
|
1442
|
+
chainId: request.authMessage.chainId,
|
|
1443
|
+
amount: request.authMessage.amount,
|
|
1444
|
+
action: request.authMessage.action,
|
|
1445
|
+
signature: request.userSignature,
|
|
1446
|
+
mode: request.authMessage.mode,
|
|
1447
|
+
...(request.authMessage.contracts && {
|
|
1448
|
+
contracts: request.authMessage.contracts,
|
|
1449
|
+
}),
|
|
1450
|
+
},
|
|
1451
|
+
amount: request.authMessage.amount,
|
|
1452
|
+
};
|
|
1453
|
+
// Add custom RPC URL for local development (ngrok tunnels)
|
|
1454
|
+
if (request.customRpcUrl) {
|
|
1455
|
+
litActionParams.customRpcUrl = request.customRpcUrl;
|
|
1456
|
+
if (this.config.debug) {
|
|
1457
|
+
console.log(" Custom RPC URL:", request.customRpcUrl);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
// Execute LIT Action (single attempt - retry logic is in SDK layer)
|
|
1602
1461
|
const result = await this.actionExecutor.executeAction({
|
|
1603
1462
|
cid: litActionInfo.cid,
|
|
1604
1463
|
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
|
-
},
|
|
1464
|
+
params: litActionParams,
|
|
1614
1465
|
signer: this.config.signer,
|
|
1615
1466
|
}, litClient);
|
|
1616
1467
|
if (this.config.debug) {
|
|
@@ -1624,7 +1475,7 @@ class LitOps {
|
|
|
1624
1475
|
}
|
|
1625
1476
|
// Parse response if it's a string (LIT Actions return JSON as string)
|
|
1626
1477
|
let responseData = result.response;
|
|
1627
|
-
if (typeof result.response ===
|
|
1478
|
+
if (typeof result.response === "string") {
|
|
1628
1479
|
try {
|
|
1629
1480
|
responseData = JSON.parse(result.response);
|
|
1630
1481
|
if (this.config.debug) {
|
|
@@ -1641,12 +1492,59 @@ class LitOps {
|
|
|
1641
1492
|
console.log("🔍 responseData (FULL OBJECT):", JSON.stringify(responseData, null, 2));
|
|
1642
1493
|
console.log("🔍 responseData keys:", Object.keys(responseData || {}));
|
|
1643
1494
|
}
|
|
1495
|
+
// Extract actual signature from Lit Action execution result
|
|
1496
|
+
// The signature is in result.signatures.ucdMintAuth.signature (not in response JSON)
|
|
1497
|
+
let actualSignature;
|
|
1498
|
+
try {
|
|
1499
|
+
if (result.signatures && typeof result.signatures === 'object') {
|
|
1500
|
+
const signatures = result.signatures;
|
|
1501
|
+
if (signatures.ucdMintAuth && signatures.ucdMintAuth.signature) {
|
|
1502
|
+
const sig = signatures.ucdMintAuth.signature;
|
|
1503
|
+
if (typeof sig === 'string' && sig !== 'success') {
|
|
1504
|
+
actualSignature = sig;
|
|
1505
|
+
if (this.config.debug) {
|
|
1506
|
+
console.log('✅ Extracted signature from Lit Action execution result', {
|
|
1507
|
+
signatureLength: actualSignature.length,
|
|
1508
|
+
signaturePreview: actualSignature.substring(0, 20) + '...',
|
|
1509
|
+
});
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
else if (this.config.debug) {
|
|
1513
|
+
console.warn('⚠️ Signature in Lit Action result is not a valid string', {
|
|
1514
|
+
signatureType: typeof sig,
|
|
1515
|
+
signatureValue: sig,
|
|
1516
|
+
});
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
else if (this.config.debug) {
|
|
1520
|
+
console.warn('⚠️ No ucdMintAuth signature found in Lit Action execution result', {
|
|
1521
|
+
signaturesKeys: Object.keys(signatures),
|
|
1522
|
+
});
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
else if (this.config.debug) {
|
|
1526
|
+
console.warn('⚠️ Lit Action execution result has no signatures object', {
|
|
1527
|
+
hasSignatures: !!result.signatures,
|
|
1528
|
+
signaturesType: typeof result.signatures,
|
|
1529
|
+
});
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
catch (sigError) {
|
|
1533
|
+
// Don't fail authorization if signature extraction fails - signature is optional
|
|
1534
|
+
if (this.config.debug) {
|
|
1535
|
+
console.warn('⚠️ Error extracting signature from Lit Action result (non-fatal)', {
|
|
1536
|
+
error: sigError instanceof Error ? sigError.message : String(sigError),
|
|
1537
|
+
});
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
// Ensure signature is a hex string (add 0x prefix if missing)
|
|
1541
|
+
if (actualSignature && !actualSignature.startsWith("0x")) {
|
|
1542
|
+
actualSignature = "0x" + actualSignature;
|
|
1543
|
+
}
|
|
1644
1544
|
// Return standardized response
|
|
1645
1545
|
const returnValue = {
|
|
1646
1546
|
approved: responseData?.approved ?? false,
|
|
1647
|
-
signature:
|
|
1648
|
-
? JSON.stringify(result.signatures)
|
|
1649
|
-
: undefined,
|
|
1547
|
+
signature: actualSignature, // Return extracted hex string directly (matching pkp-authorization.module.ts pattern)
|
|
1650
1548
|
mintAmount: responseData?.mintAmount,
|
|
1651
1549
|
mintFee: responseData?.mintFee,
|
|
1652
1550
|
newDebt: responseData?.newDebt,
|
|
@@ -1829,6 +1727,126 @@ class LitOps {
|
|
|
1829
1727
|
results,
|
|
1830
1728
|
};
|
|
1831
1729
|
}
|
|
1730
|
+
/**
|
|
1731
|
+
* NOLA (No LIT Action) - Vault Snapshot
|
|
1732
|
+
*
|
|
1733
|
+
* Cost-optimized data access for position health metrics.
|
|
1734
|
+
* Executes vault-snapshot logic in Node.js without paying for LIT Action execution.
|
|
1735
|
+
*
|
|
1736
|
+
* Modes:
|
|
1737
|
+
* - Standalone: Calls executeVaultSnapshot directly with provided RPC URLs
|
|
1738
|
+
* - Service: Sends request to lit-ops-server which provides credentials
|
|
1739
|
+
*
|
|
1740
|
+
* @param params - Position and network configuration
|
|
1741
|
+
* @returns Complete VaultSnapshot with position health data
|
|
1742
|
+
/
|
|
1743
|
+
async getVaultSnapshot(params: {
|
|
1744
|
+
positionId: string;
|
|
1745
|
+
network: "sepolia" | "ethereum" | "localhost";
|
|
1746
|
+
// Standalone mode requires these:
|
|
1747
|
+
contractAddress?: string;
|
|
1748
|
+
termManagerAddress?: string;
|
|
1749
|
+
loanOpsManagerAddress?: string;
|
|
1750
|
+
chainId?: number;
|
|
1751
|
+
rpcUrl?: string;
|
|
1752
|
+
bitcoinProviderUrl?: string;
|
|
1753
|
+
minConfirmations?: number;
|
|
1754
|
+
}) {
|
|
1755
|
+
if (this.config.mode === "standalone") {
|
|
1756
|
+
// Standalone mode: Direct execution with provided credentials
|
|
1757
|
+
if (
|
|
1758
|
+
!params.contractAddress ||
|
|
1759
|
+
!params.rpcUrl ||
|
|
1760
|
+
!params.bitcoinProviderUrl
|
|
1761
|
+
) {
|
|
1762
|
+
throw new Error(
|
|
1763
|
+
"Standalone mode requires: contractAddress, rpcUrl, bitcoinProviderUrl"
|
|
1764
|
+
);
|
|
1765
|
+
}
|
|
1766
|
+
if (!params.termManagerAddress || !params.loanOpsManagerAddress) {
|
|
1767
|
+
throw new Error(
|
|
1768
|
+
"Standalone mode requires: termManagerAddress, loanOpsManagerAddress"
|
|
1769
|
+
);
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
// Import NOLA executor
|
|
1773
|
+
const { executeVaultSnapshot } = await import("@gvnrdao/dh-lit-actions");
|
|
1774
|
+
|
|
1775
|
+
// Execute directly
|
|
1776
|
+
return await executeVaultSnapshot({
|
|
1777
|
+
positionId: params.positionId,
|
|
1778
|
+
contractAddress: params.contractAddress,
|
|
1779
|
+
termManagerAddress: params.termManagerAddress,
|
|
1780
|
+
loanOpsManagerAddress: params.loanOpsManagerAddress,
|
|
1781
|
+
chain: params.network,
|
|
1782
|
+
chainId: params.chainId,
|
|
1783
|
+
rpcUrl: params.rpcUrl,
|
|
1784
|
+
bitcoinProviderUrl: params.bitcoinProviderUrl,
|
|
1785
|
+
minConfirmations: params.minConfirmations || 6,
|
|
1786
|
+
});
|
|
1787
|
+
} else {
|
|
1788
|
+
// Service mode: Call lit-ops-server endpoint
|
|
1789
|
+
if (!this.config.serviceEndpoint) {
|
|
1790
|
+
throw new Error("serviceEndpoint is required for service mode");
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
const response = await fetch(
|
|
1794
|
+
`${this.config.serviceEndpoint}/api/lit/nola/vault-snapshot`,
|
|
1795
|
+
{
|
|
1796
|
+
method: "POST",
|
|
1797
|
+
headers: {
|
|
1798
|
+
"Content-Type": "application/json",
|
|
1799
|
+
},
|
|
1800
|
+
body: JSON.stringify({
|
|
1801
|
+
positionId: params.positionId,
|
|
1802
|
+
network: params.network,
|
|
1803
|
+
}),
|
|
1804
|
+
}
|
|
1805
|
+
);
|
|
1806
|
+
|
|
1807
|
+
if (!response.ok) {
|
|
1808
|
+
const errorText = await response.text();
|
|
1809
|
+
throw new Error(
|
|
1810
|
+
`NOLA service request failed: ${response.status} ${errorText}`
|
|
1811
|
+
);
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
const apiResponse: any = await response.json();
|
|
1815
|
+
|
|
1816
|
+
// Convert string BigInts back to BigInt type
|
|
1817
|
+
const convertStringsToBigInt = (obj: any): any => {
|
|
1818
|
+
if (obj === null || obj === undefined) return obj;
|
|
1819
|
+
|
|
1820
|
+
if (typeof obj === "string") {
|
|
1821
|
+
// Check if string is a valid BigInt representation
|
|
1822
|
+
if (/^\d+$/.test(obj)) {
|
|
1823
|
+
try {
|
|
1824
|
+
return BigInt(obj);
|
|
1825
|
+
} catch {
|
|
1826
|
+
return obj;
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
return obj;
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
if (Array.isArray(obj)) {
|
|
1833
|
+
return obj.map(convertStringsToBigInt);
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
if (typeof obj === "object") {
|
|
1837
|
+
const converted: any = {};
|
|
1838
|
+
for (const key in obj) {
|
|
1839
|
+
converted[key] = convertStringsToBigInt(obj[key]);
|
|
1840
|
+
}
|
|
1841
|
+
return converted;
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
return obj;
|
|
1845
|
+
};
|
|
1846
|
+
|
|
1847
|
+
return convertStringsToBigInt(apiResponse.data); // Unwrap and convert
|
|
1848
|
+
}
|
|
1849
|
+
} */
|
|
1832
1850
|
async disconnect() {
|
|
1833
1851
|
// Ensure capacity module timers are cleaned up first
|
|
1834
1852
|
try {
|