@gvnrdao/dh-lit-ops 0.0.61 → 0.0.75

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.
@@ -649,44 +649,28 @@ class LitOps {
649
649
  // Get the PKP validator CID
650
650
  const pkpValidatorCid = (this.config.network === "datil"
651
651
  ? dh_lit_actions_1.DH_LIT_ACTIONS_DATIL
652
- : dh_lit_actions_1.DH_LIT_ACTIONS_DATIL_TEST).pkpValidator.cid;
652
+ : (() => {
653
+ throw new Error("Unsupported LIT network");
654
+ })()).pkpValidator.cid;
653
655
  if (this.config.debug) {
654
656
  console.log(` PKP Validator CID: ${pkpValidatorCid}`);
655
657
  }
656
658
  // Execute PKP Validator LIT Action
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.
659
+ // NOTE: We do NOT pass the validator PKP token ID here because the validator
660
+ // performs READ-ONLY operations (no signing). Passing undefined for pkpTokenId
661
+ // will skip adding LitPKPResource to the session signature, which is correct
662
+ // for burned/immutable validator PKPs that can't sign via session signatures.
661
663
  console.log(`\nšŸ” LIT-OPS TRACE: About to call executeActionFromCID with jsParams:`);
662
664
  console.log(` - targetPkpTokenId: "${targetPkpTokenId}"`);
663
665
  console.log(` - expectedCid: "${expectedCid}"`);
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
- }
682
666
  const litResult = await this.executeActionFromCID(pkpValidatorCid, signerPkp.publicKey, {
683
667
  targetPkpTokenId,
684
- expectedCid, // PKP's LIT Action CID (for validation check)
685
- certificationCid: validatorCidHex, // Validator's CID (for signature message)
668
+ expectedCid, // Expected to be in hex format
686
669
  message: `PKP validation: ${Date.now()}`,
687
670
  // Ensure the LIT Action knows which network (datil vs datil-test)
688
671
  network: this.config.network,
689
- }, signer, sessionScopedSignerTokenId, signerPkp.ethAddress // Required for capacity delegation on Datil
672
+ }, signer
673
+ // Intentionally NOT passing signerPkp.tokenId - validator is read-only
690
674
  );
691
675
  if (this.config.debug) {
692
676
  console.log(` LIT Action Success: ${litResult.success}`);
@@ -1245,7 +1229,9 @@ class LitOps {
1245
1229
  console.log("šŸŽÆ Creating new Diamond Hands Loan PKP");
1246
1230
  console.log(" Using authorization CID:", (networkOverride ?? this.config.network) === "datil"
1247
1231
  ? dh_lit_actions_1.DH_LIT_ACTIONS_DATIL.authorizationDummy.cid
1248
- : dh_lit_actions_1.DH_LIT_ACTIONS_DATIL_TEST.authorizationDummy.cid);
1232
+ : (() => {
1233
+ throw new Error("Unsupported LIT network");
1234
+ })());
1249
1235
  console.log(` Mode: ${this.config.mode}`);
1250
1236
  if (networkOverride) {
1251
1237
  console.log(" Network override:", networkOverride);
@@ -1258,12 +1244,16 @@ class LitOps {
1258
1244
  throw new Error("Signer is required for standalone mode");
1259
1245
  }
1260
1246
  const selectedNetwork = networkOverride ?? this.config.network;
1261
- const authDummyCid = (selectedNetwork === "datil"
1247
+ const registry = selectedNetwork === "datil"
1262
1248
  ? dh_lit_actions_1.DH_LIT_ACTIONS_DATIL
1263
- : dh_lit_actions_1.DH_LIT_ACTIONS_DATIL_TEST).authorizationDummy.cid;
1249
+ : (() => {
1250
+ throw new Error("Unsupported LIT network");
1251
+ })();
1252
+ // Vault PKP must authorize btcTransactionSigner for Bitcoin transaction signing
1253
+ const btcTxSignerCid = registry.btcTransactionSigner.cid;
1264
1254
  console.log(`šŸ” LIT-OPS TRACE: getNewDiamondHandsLoanPkp - selectedNetwork = "${selectedNetwork}"`);
1265
- console.log(`šŸ” LIT-OPS TRACE: getNewDiamondHandsLoanPkp - authorizationDummy.cid = "${authDummyCid}"`);
1266
- return this.createAndValidatePkpToLitAction(authDummyCid, effectiveSigner);
1255
+ console.log(`šŸ” LIT-OPS TRACE: getNewDiamondHandsLoanPkp - btcTransactionSigner.cid = "${btcTxSignerCid}"`);
1256
+ return this.createAndValidatePkpToLitAction(btcTxSignerCid, effectiveSigner);
1267
1257
  }
1268
1258
  /**
1269
1259
  * Request mint authorization from UCD Mint Validator LIT Action
@@ -1303,6 +1293,125 @@ class LitOps {
1303
1293
  }
1304
1294
  return this.requestMintAuthorizationStandalone(request);
1305
1295
  }
1296
+ /**
1297
+ * DEV ONLY: Run BTC Always Signer LIT Action
1298
+ * Intermediate testing tool for Bitcoin transaction structure validation
1299
+ * Signs Bitcoin transactions WITHOUT authorization checks
1300
+ *
1301
+ * @param request - Bitcoin transaction parameters
1302
+ * @returns Signature result with transaction structure
1303
+ */
1304
+ async runBtcAlwaysSigner(request) {
1305
+ if (this.config.debug) {
1306
+ console.log("šŸ”§ [runBtcAlwaysSigner] DEV MODE ONLY");
1307
+ console.log(" Mode:", this.config.mode);
1308
+ }
1309
+ // Service mode: Call server endpoint
1310
+ if (this.config.mode === "service") {
1311
+ return this.runBtcAlwaysSignerViaService(request);
1312
+ }
1313
+ // Standalone mode: Execute locally
1314
+ return this.runBtcAlwaysSignerStandalone(request);
1315
+ }
1316
+ /**
1317
+ * Run BTC Always Signer via service (SERVICE mode)
1318
+ */
1319
+ async runBtcAlwaysSignerViaService(request) {
1320
+ if (!this.config.serviceEndpoint) {
1321
+ throw new Error("Service endpoint not configured for service mode");
1322
+ }
1323
+ const url = `${this.config.serviceEndpoint}/api/lit/dev/btc-always-signer`;
1324
+ if (this.config.debug) {
1325
+ console.log("🌐 Running BTC always-signer via service:", url);
1326
+ console.log(" Destination:", request.destination);
1327
+ console.log(" Amount:", request.amount);
1328
+ }
1329
+ try {
1330
+ const response = await fetch(url, {
1331
+ method: "POST",
1332
+ headers: {
1333
+ "Content-Type": "application/json",
1334
+ },
1335
+ body: JSON.stringify(request),
1336
+ });
1337
+ if (!response.ok) {
1338
+ const errorText = await response.text();
1339
+ throw new Error(`Service error (${response.status}): ${errorText}`);
1340
+ }
1341
+ const result = (await response.json());
1342
+ if (this.config.debug) {
1343
+ console.log("āœ… BTC always-signer completed via service");
1344
+ }
1345
+ return result.data || result;
1346
+ }
1347
+ catch (error) {
1348
+ if (this.config.debug) {
1349
+ console.error("āŒ Service BTC always-signer failed:", error);
1350
+ }
1351
+ return {
1352
+ success: false,
1353
+ error: error instanceof Error ? error.message : String(error),
1354
+ };
1355
+ }
1356
+ }
1357
+ /**
1358
+ * Run BTC Always Signer locally (STANDALONE mode)
1359
+ */
1360
+ async runBtcAlwaysSignerStandalone(request) {
1361
+ // Get always-signer LIT Action CID
1362
+ const alwaysSignerCid = "QmRcQTDiZJq5arXngdxCX1LPnTW1fvx78tBD9vZmMXg8Ly";
1363
+ if (this.config.debug) {
1364
+ console.log("šŸ“” Calling BTC Always Signer LIT Action:");
1365
+ console.log(" CID:", alwaysSignerCid);
1366
+ console.log(" Destination:", request.destination);
1367
+ console.log(" Amount:", request.amount);
1368
+ }
1369
+ try {
1370
+ // Execute LIT Action
1371
+ // NOTE: The always-signer LIT Action expects params in (globalThis as any).params
1372
+ // so we nest the parameters under a 'params' key
1373
+ const result = await this.executeActionFromCID(alwaysSignerCid, request.pkpPublicKey, {
1374
+ params: {
1375
+ amount: request.amount,
1376
+ fee: request.fee,
1377
+ destination: request.destination,
1378
+ utxo: request.utxo,
1379
+ network: request.network,
1380
+ pkpPublicKey: request.pkpPublicKey,
1381
+ },
1382
+ }, this.config.signer, // Use signer from LitOps config
1383
+ undefined, // No PKP token ID needed
1384
+ undefined // No PKP ETH address needed
1385
+ );
1386
+ if (this.config.debug) {
1387
+ console.log("āœ… BTC Always Signer executed");
1388
+ console.log(" Success:", result.success);
1389
+ }
1390
+ // Parse response
1391
+ const response = typeof result.response === "string"
1392
+ ? JSON.parse(result.response)
1393
+ : result.response;
1394
+ // Extract actual signature from LIT SDK response
1395
+ // LIT SDK puts signatures in result.signatures.btcTxSig
1396
+ if (result.signatures?.btcTxSig) {
1397
+ response.signature = {
1398
+ r: result.signatures.btcTxSig.r,
1399
+ s: result.signatures.btcTxSig.s,
1400
+ recid: result.signatures.btcTxSig.recid,
1401
+ };
1402
+ }
1403
+ return response;
1404
+ }
1405
+ catch (error) {
1406
+ if (this.config.debug) {
1407
+ console.error("āŒ BTC Always Signer failed:", error);
1408
+ }
1409
+ return {
1410
+ success: false,
1411
+ error: error instanceof Error ? error.message : String(error),
1412
+ };
1413
+ }
1414
+ }
1306
1415
  /**
1307
1416
  * Request mint authorization via lit-ops-server (SERVICE mode)
1308
1417
  */
@@ -1379,7 +1488,9 @@ class LitOps {
1379
1488
  // Get LIT Action info from registry
1380
1489
  const litActions = this.config.network === "datil"
1381
1490
  ? dh_lit_actions_1.DH_LIT_ACTIONS_DATIL
1382
- : dh_lit_actions_1.DH_LIT_ACTIONS_DATIL_TEST;
1491
+ : (() => {
1492
+ throw new Error("Unsupported LIT network");
1493
+ })();
1383
1494
  const litActionInfo = litActions.ucdMintValidator;
1384
1495
  if (!litActionInfo || !litActionInfo.cid || !litActionInfo.pkp) {
1385
1496
  throw new Error("UCD mint validator LIT Action not found in registry");
@@ -1410,7 +1521,7 @@ class LitOps {
1410
1521
  chain = "sepolia";
1411
1522
  bitcoinProviderUrl =
1412
1523
  process.env.BITCOIN_PROVIDER_URL ||
1413
- "https://diamond-hands-btc-faucet-6b39a1072059.herokuapp.com/api";
1524
+ "https://diamond-hands-btc-faucet-jw-b86e9451a147.herokuapp.com/api";
1414
1525
  break;
1415
1526
  case 1337: // Hardhat local testnet (actual deployment chainId)
1416
1527
  case 31337: // Hardhat local testnet (standard default)
@@ -1442,11 +1553,12 @@ class LitOps {
1442
1553
  action: request.authMessage.action,
1443
1554
  signature: request.userSignature,
1444
1555
  mode: request.authMessage.mode,
1445
- ...(request.authMessage.contracts && {
1446
- contracts: request.authMessage.contracts,
1447
- }),
1448
1556
  },
1449
1557
  amount: request.authMessage.amount,
1558
+ // Contracts must be at top level to become globalThis.contracts in LIT Action
1559
+ ...(request.authMessage.contracts && {
1560
+ contracts: request.authMessage.contracts,
1561
+ }),
1450
1562
  };
1451
1563
  // Add custom RPC URL for local development (ngrok tunnels)
1452
1564
  if (request.customRpcUrl) {
@@ -1461,6 +1573,7 @@ class LitOps {
1461
1573
  pkpPublicKey: litActionInfo.pkp.publicKey,
1462
1574
  params: litActionParams,
1463
1575
  signer: this.config.signer,
1576
+ priceProviders: request.priceProviders, // Pass price provider API keys (standalone mode)
1464
1577
  }, litClient);
1465
1578
  if (this.config.debug) {
1466
1579
  console.log("šŸ“„ LIT Action response:", {
@@ -1514,6 +1627,477 @@ class LitOps {
1514
1627
  }
1515
1628
  return returnValue;
1516
1629
  }
1630
+ /**
1631
+ * Request BTC withdrawal authorization (dual-mode)
1632
+ *
1633
+ * @param request - Authorization request with authMessage and userSignature
1634
+ * @returns Withdrawal authorization response from LIT Action
1635
+ */
1636
+ async requestWithdrawalAuthorization(request) {
1637
+ // In SERVICE mode, delegate to lit-ops-server
1638
+ if (this.config.mode === "service") {
1639
+ if (this.config.debug) {
1640
+ console.log("🌐 [requestWithdrawalAuthorization] Using SERVICE mode - delegating to server");
1641
+ }
1642
+ return this.requestWithdrawalAuthorizationViaService(request);
1643
+ }
1644
+ // STANDALONE mode: Execute LIT action locally
1645
+ if (this.config.debug) {
1646
+ console.log("šŸ”§ [requestWithdrawalAuthorization] Using STANDALONE mode - executing locally");
1647
+ }
1648
+ return this.requestWithdrawalAuthorizationStandalone(request);
1649
+ }
1650
+ /**
1651
+ * Request withdrawal authorization via lit-ops-server (SERVICE mode)
1652
+ */
1653
+ async requestWithdrawalAuthorizationViaService(request) {
1654
+ if (!this.config.serviceEndpoint) {
1655
+ throw new Error("Service endpoint not configured for service mode");
1656
+ }
1657
+ const url = `${this.config.serviceEndpoint}/api/lit/withdraw-btc/authorize`;
1658
+ if (this.config.debug) {
1659
+ console.log("🌐 Requesting withdrawal authorization via service:", url);
1660
+ console.log(" Position ID:", request.authMessage.positionId);
1661
+ console.log(" Amount:", request.authMessage.amount);
1662
+ console.log(" Address:", request.authMessage.withdrawalAddress);
1663
+ }
1664
+ try {
1665
+ // Transform authMessage: SDK uses withdrawalAddress, server expects destinationAddress
1666
+ const transformedAuthMessage = {
1667
+ ...request.authMessage,
1668
+ destinationAddress: request.authMessage.withdrawalAddress,
1669
+ };
1670
+ // Remove withdrawalAddress from the transformed message
1671
+ delete transformedAuthMessage.withdrawalAddress;
1672
+ const response = await fetch(url, {
1673
+ method: "POST",
1674
+ headers: {
1675
+ "Content-Type": "application/json",
1676
+ },
1677
+ body: JSON.stringify({
1678
+ authMessage: transformedAuthMessage,
1679
+ userSignature: request.userSignature,
1680
+ customRpcUrl: request.customRpcUrl,
1681
+ customBitcoinRpcUrl: request.customBitcoinRpcUrl,
1682
+ }),
1683
+ });
1684
+ if (!response.ok) {
1685
+ const errorText = await response.text();
1686
+ throw new Error(`Service error (${response.status}): ${errorText}`);
1687
+ }
1688
+ const envelope = await response.json();
1689
+ if (this.config.debug) {
1690
+ console.log("šŸ“„ Service response:", envelope);
1691
+ }
1692
+ // Extract data from envelope (server wraps in { success, data } structure)
1693
+ const result = envelope.data || envelope;
1694
+ // Return the result from service
1695
+ return {
1696
+ approved: result.approved ?? false,
1697
+ signature: result.signature,
1698
+ actionHash: result.actionHash,
1699
+ authorizedSpendsHash: result.authorizedSpendsHash,
1700
+ ucdDebtHash: result.ucdDebtHash,
1701
+ totalDeduction: result.totalDeduction,
1702
+ remainingCollateral: result.remainingCollateral,
1703
+ newCollateralRatioBps: result.newCollateralRatioBps,
1704
+ destinationAddress: result.destinationAddress,
1705
+ btcPrice: result.btcPrice,
1706
+ timestamp: result.timestamp,
1707
+ utxoTxid: result.utxoTxid,
1708
+ utxoVout: result.utxoVout,
1709
+ utxoSatoshis: result.utxoSatoshis,
1710
+ reason: result.reason,
1711
+ failedStep: result.failedStep,
1712
+ error: result.error,
1713
+ };
1714
+ }
1715
+ catch (error) {
1716
+ console.error("āŒ Service request failed:", error);
1717
+ return {
1718
+ approved: false,
1719
+ error: error instanceof Error ? error.message : String(error),
1720
+ reason: "Service request failed",
1721
+ };
1722
+ }
1723
+ }
1724
+ /**
1725
+ * Request withdrawal authorization locally (STANDALONE mode)
1726
+ */
1727
+ async requestWithdrawalAuthorizationStandalone(request) {
1728
+ // Get LIT Action info from registry
1729
+ const litActions = this.config.network === "datil"
1730
+ ? dh_lit_actions_1.DH_LIT_ACTIONS_DATIL
1731
+ : (() => {
1732
+ throw new Error("Unsupported LIT network");
1733
+ })();
1734
+ const litActionInfo = litActions.btcWithdrawal;
1735
+ if (!litActionInfo || !litActionInfo.cid || !litActionInfo.pkp) {
1736
+ throw new Error("BTC withdrawal LIT Action not found in registry");
1737
+ }
1738
+ if (this.config.debug) {
1739
+ console.log("šŸ“” Calling BTC Withdrawal LIT Action:");
1740
+ console.log(" Network:", this.config.network);
1741
+ console.log(" CID:", litActionInfo.cid);
1742
+ console.log(" Position:", request.authMessage.positionId);
1743
+ console.log(" Amount:", request.authMessage.amount);
1744
+ console.log(" Address:", request.authMessage.withdrawalAddress);
1745
+ console.log(" Timestamp:", request.authMessage.timestamp);
1746
+ }
1747
+ // Get LIT client for execution
1748
+ const litClient = await this.clientManager.getClient({
1749
+ litNetwork: this.config.network,
1750
+ debug: this.config.debug,
1751
+ });
1752
+ // Determine chain and Bitcoin provider from chainId
1753
+ let chain;
1754
+ let bitcoinProviderUrl;
1755
+ switch (request.authMessage.chainId) {
1756
+ case 1: // Ethereum mainnet
1757
+ chain = "ethereum";
1758
+ bitcoinProviderUrl =
1759
+ process.env.BITCOIN_PROVIDER_URL || "https://mempool.space/api";
1760
+ break;
1761
+ case 11155111: // Sepolia testnet
1762
+ chain = "sepolia";
1763
+ bitcoinProviderUrl =
1764
+ process.env.BITCOIN_PROVIDER_URL ||
1765
+ "https://diamond-hands-btc-faucet-jw-b86e9451a147.herokuapp.com/api";
1766
+ break;
1767
+ case 1337: // Hardhat local testnet (actual deployment chainId)
1768
+ case 31337: // Hardhat local testnet (standard default)
1769
+ chain = "hardhat";
1770
+ bitcoinProviderUrl =
1771
+ process.env.BITCOIN_PROVIDER_URL || "http://127.0.0.1:18443";
1772
+ break;
1773
+ default:
1774
+ throw new Error(`Unsupported chainId: ${request.authMessage.chainId}`);
1775
+ }
1776
+ // Override with custom Bitcoin RPC URL if provided
1777
+ if (request.customBitcoinRpcUrl) {
1778
+ bitcoinProviderUrl = request.customBitcoinRpcUrl;
1779
+ if (this.config.debug) {
1780
+ console.log(" Custom Bitcoin RPC URL:", request.customBitcoinRpcUrl);
1781
+ }
1782
+ }
1783
+ // Execute LIT Action
1784
+ const litActionParams = {
1785
+ chain,
1786
+ bitcoinProviderUrl,
1787
+ auth: {
1788
+ positionId: request.authMessage.positionId,
1789
+ timestamp: request.authMessage.timestamp,
1790
+ chainId: request.authMessage.chainId,
1791
+ destinationAddress: request.authMessage.withdrawalAddress,
1792
+ amount: request.authMessage.amount,
1793
+ action: request.authMessage.action,
1794
+ signature: request.userSignature,
1795
+ mode: request.authMessage.mode,
1796
+ },
1797
+ // Always pass contracts (undefined in prod mode)
1798
+ contracts: request.authMessage.contracts,
1799
+ };
1800
+ // Add custom RPC URL for local development
1801
+ if (request.customRpcUrl) {
1802
+ litActionParams.customRpcUrl = request.customRpcUrl;
1803
+ if (this.config.debug) {
1804
+ console.log(" Custom RPC URL:", request.customRpcUrl);
1805
+ }
1806
+ }
1807
+ // Execute LIT Action
1808
+ const result = await this.actionExecutor.executeAction({
1809
+ cid: litActionInfo.cid,
1810
+ pkpPublicKey: litActionInfo.pkp.publicKey,
1811
+ params: litActionParams,
1812
+ signer: this.config.signer,
1813
+ }, litClient);
1814
+ if (this.config.debug) {
1815
+ console.log("šŸ“„ LIT Action response:", {
1816
+ success: result.success,
1817
+ hasSignature: !!result.signatures,
1818
+ error: result.error,
1819
+ });
1820
+ console.log("šŸ“„ LIT Action result.response (raw):", result.response);
1821
+ }
1822
+ // Parse response if it's a string
1823
+ let responseData = result.response;
1824
+ if (typeof result.response === "string") {
1825
+ try {
1826
+ responseData = JSON.parse(result.response);
1827
+ if (this.config.debug) {
1828
+ console.log("šŸ“„ Parsed response data:", responseData);
1829
+ }
1830
+ }
1831
+ catch (e) {
1832
+ if (this.config.debug) {
1833
+ console.error("āŒ Failed to parse response string:", e);
1834
+ }
1835
+ }
1836
+ }
1837
+ // Return standardized response including UTXO data from Bitcoin network query
1838
+ const returnValue = {
1839
+ approved: responseData?.approved ?? false,
1840
+ signature: result.signatures
1841
+ ? JSON.stringify(result.signatures)
1842
+ : undefined,
1843
+ actionHash: responseData?.actionHash,
1844
+ authorizedSpendsHash: responseData?.authorizedSpendsHash,
1845
+ ucdDebtHash: responseData?.ucdDebtHash,
1846
+ totalDeduction: responseData?.totalDeduction,
1847
+ remainingCollateral: responseData?.remainingCollateral,
1848
+ newCollateralRatioBps: responseData?.newCollateralRatioBps,
1849
+ destinationAddress: responseData?.destinationAddress,
1850
+ btcPrice: responseData?.btcPrice,
1851
+ timestamp: responseData?.timestamp,
1852
+ utxoTxid: responseData?.utxoTxid, // Real Bitcoin UTXO txid from network query
1853
+ utxoVout: responseData?.utxoVout, // Real Bitcoin UTXO vout from network query
1854
+ utxoSatoshis: responseData?.utxoSatoshis, // UTXO value for validation
1855
+ reason: responseData?.reason,
1856
+ failedStep: responseData?.failedStep,
1857
+ error: result.error,
1858
+ };
1859
+ if (this.config.debug) {
1860
+ console.log("šŸŽ STANDALONE RETURN VALUE:", JSON.stringify(returnValue, null, 2));
1861
+ }
1862
+ return returnValue;
1863
+ }
1864
+ /**
1865
+ * Sign Bitcoin transaction for BTC withdrawal execution (Phase 2)
1866
+ *
1867
+ * Dual-mode method: Delegates to service endpoint or executes locally
1868
+ */
1869
+ async signBTCTransaction(request) {
1870
+ // In SERVICE mode, delegate to lit-ops-server
1871
+ if (this.config.mode === "service") {
1872
+ if (this.config.debug) {
1873
+ console.log("🌐 [signBTCTransaction] Using SERVICE mode - delegating to server");
1874
+ }
1875
+ return this.signBTCTransactionViaService(request);
1876
+ }
1877
+ // STANDALONE mode: Execute LIT action locally
1878
+ if (this.config.debug) {
1879
+ console.log("šŸ”§ [signBTCTransaction] Using STANDALONE mode - executing locally");
1880
+ }
1881
+ return this.signBTCTransactionStandalone(request);
1882
+ }
1883
+ /**
1884
+ * Sign Bitcoin transaction via lit-ops-server (SERVICE mode)
1885
+ */
1886
+ async signBTCTransactionViaService(request) {
1887
+ if (!this.config.serviceEndpoint) {
1888
+ throw new Error("Service endpoint not configured for service mode");
1889
+ }
1890
+ const url = `${this.config.serviceEndpoint}/api/lit/btc/sign-transaction`;
1891
+ if (this.config.debug) {
1892
+ console.log("🌐 Signing BTC transaction via service:", url);
1893
+ console.log(" Position ID:", request.auth.positionId);
1894
+ console.log(" UTXO:", `${request.auth.utxo.txid}:${request.auth.utxo.vout}`);
1895
+ console.log(" Network Fee:", request.auth.networkFee);
1896
+ }
1897
+ try {
1898
+ const response = await fetch(url, {
1899
+ method: "POST",
1900
+ headers: {
1901
+ "Content-Type": "application/json",
1902
+ },
1903
+ body: JSON.stringify(request),
1904
+ });
1905
+ if (!response.ok) {
1906
+ const errorText = await response.text();
1907
+ throw new Error(`Service error (${response.status}): ${errorText}`);
1908
+ }
1909
+ const envelope = await response.json();
1910
+ if (this.config.debug) {
1911
+ console.log("šŸ“„ Service response:", envelope);
1912
+ }
1913
+ // Extract data from envelope (server wraps in { success, data } structure)
1914
+ const result = envelope.data || envelope;
1915
+ return {
1916
+ success: result.success ?? false,
1917
+ unsignedTxHex: result.unsignedTxHex,
1918
+ sigHash: result.sigHash,
1919
+ signature: result.signature,
1920
+ pkpPublicKey: result.pkpPublicKey,
1921
+ pkpBtcAddress: result.pkpBtcAddress,
1922
+ destination: result.destination,
1923
+ userReceivesAmount: result.userReceivesAmount,
1924
+ networkFee: result.networkFee,
1925
+ changeAmount: result.changeAmount,
1926
+ utxo: result.utxo,
1927
+ authorization: result.authorization,
1928
+ timestamp: result.timestamp,
1929
+ action: result.action,
1930
+ error: result.error,
1931
+ failedStep: result.failedStep,
1932
+ };
1933
+ }
1934
+ catch (error) {
1935
+ console.error("āŒ Service request failed:", error);
1936
+ return {
1937
+ success: false,
1938
+ error: error instanceof Error ? error.message : String(error),
1939
+ };
1940
+ }
1941
+ }
1942
+ /**
1943
+ * Sign Bitcoin transaction locally (STANDALONE mode)
1944
+ */
1945
+ async signBTCTransactionStandalone(request) {
1946
+ // Get LIT Action info from registry
1947
+ const litActions = this.config.network === "datil"
1948
+ ? dh_lit_actions_1.DH_LIT_ACTIONS_DATIL
1949
+ : (() => {
1950
+ throw new Error("Unsupported LIT network");
1951
+ })();
1952
+ const litActionInfo = litActions.btcTransactionSigner;
1953
+ if (!litActionInfo || !litActionInfo.cid) {
1954
+ throw new Error("BTC transaction signer LIT Action not found in registry");
1955
+ }
1956
+ if (this.config.debug) {
1957
+ console.log("šŸ“” Calling BTC Transaction Signer LIT Action:");
1958
+ console.log(" Network:", this.config.network);
1959
+ console.log(" CID:", litActionInfo.cid);
1960
+ console.log(" Position:", request.auth.positionId);
1961
+ console.log(" UTXO:", `${request.auth.utxo.txid}:${request.auth.utxo.vout}`);
1962
+ console.log(" Network Fee:", request.auth.networkFee);
1963
+ }
1964
+ // Get LIT client for execution
1965
+ const litClient = await this.clientManager.getClient({
1966
+ litNetwork: this.config.network,
1967
+ debug: this.config.debug,
1968
+ });
1969
+ // Build LIT Action parameters
1970
+ // Determine Bitcoin provider URL based on network
1971
+ let bitcoinProviderUrl;
1972
+ const chainId = request.auth.chainId;
1973
+ switch (chainId) {
1974
+ case 1: // Ethereum mainnet
1975
+ bitcoinProviderUrl = process.env.BITCOIN_PROVIDER_URL || "https://mempool.space/api";
1976
+ break;
1977
+ case 11155111: // Sepolia testnet
1978
+ bitcoinProviderUrl = process.env.BITCOIN_PROVIDER_URL || "https://diamond-hands-btc-faucet-jw-b86e9451a147.herokuapp.com/api";
1979
+ break;
1980
+ case 1337: // Hardhat local testnet (actual deployment chainId)
1981
+ case 31337: // Hardhat local testnet (standard default)
1982
+ bitcoinProviderUrl = process.env.BITCOIN_PROVIDER_URL || "http://127.0.0.1:18443";
1983
+ break;
1984
+ default:
1985
+ throw new Error(`Unsupported chainId: ${chainId}`);
1986
+ }
1987
+ // Override with custom Bitcoin RPC URL if provided (for local development with ngrok)
1988
+ if (request.customBitcoinRpcUrl) {
1989
+ bitcoinProviderUrl = request.customBitcoinRpcUrl;
1990
+ if (this.config.debug) {
1991
+ console.log(" Custom Bitcoin RPC URL (override):", request.customBitcoinRpcUrl);
1992
+ }
1993
+ }
1994
+ const litActionParams = {
1995
+ chain: request.chain,
1996
+ bitcoinNetwork: request.bitcoinNetwork,
1997
+ bitcoinProviderUrl, // For Bitcoin UTXO queries
1998
+ auth: request.auth,
1999
+ publicKey: request.publicKey,
2000
+ contracts: request.contracts,
2001
+ };
2002
+ // Add custom EVM RPC URL for local development (Hardhat)
2003
+ if (request.customRpcUrl) {
2004
+ litActionParams.customRpcUrl = request.customRpcUrl;
2005
+ if (this.config.debug) {
2006
+ console.log(" Custom EVM RPC URL:", request.customRpcUrl);
2007
+ }
2008
+ }
2009
+ if (this.config.debug) {
2010
+ console.log(" Bitcoin Provider URL:", bitcoinProviderUrl);
2011
+ }
2012
+ // Execute LIT Action
2013
+ const result = await this.actionExecutor.executeAction({
2014
+ cid: litActionInfo.cid,
2015
+ pkpPublicKey: request.publicKey,
2016
+ params: litActionParams,
2017
+ signer: this.config.signer,
2018
+ }, litClient);
2019
+ if (this.config.debug) {
2020
+ console.log("šŸ“„ LIT Action response:", {
2021
+ success: result.success,
2022
+ hasSignature: !!result.signatures,
2023
+ error: result.error,
2024
+ });
2025
+ // Log per-node debug information if available
2026
+ if (result.debug) {
2027
+ console.log("\nšŸ” PER-NODE DEBUG INFORMATION:");
2028
+ console.log("=====================================");
2029
+ const debugInfo = result.debug;
2030
+ if (debugInfo.allNodeResponses) {
2031
+ console.log("\nšŸ“Š All Node Responses:");
2032
+ console.log(JSON.stringify(debugInfo.allNodeResponses, null, 2));
2033
+ }
2034
+ if (debugInfo.allNodeLogs) {
2035
+ console.log("\nšŸ“ All Node Logs:");
2036
+ debugInfo.allNodeLogs.forEach((nodeLog, index) => {
2037
+ console.log(`\n--- Node ${index + 1} ---`);
2038
+ console.log(JSON.stringify(nodeLog, null, 2));
2039
+ });
2040
+ }
2041
+ if (debugInfo.rawNodeHTTPResponses) {
2042
+ console.log("\n🌐 Raw Node HTTP Responses:");
2043
+ console.log(JSON.stringify(debugInfo.rawNodeHTTPResponses, null, 2));
2044
+ }
2045
+ }
2046
+ else {
2047
+ console.log("āš ļø No per-node debug information available in result");
2048
+ }
2049
+ }
2050
+ // Parse response if it's a string
2051
+ let responseData = result.response;
2052
+ if (typeof result.response === "string") {
2053
+ try {
2054
+ responseData = JSON.parse(result.response);
2055
+ if (this.config.debug) {
2056
+ console.log("šŸ“„ Parsed response data:", responseData);
2057
+ }
2058
+ }
2059
+ catch (e) {
2060
+ if (this.config.debug) {
2061
+ console.error("āŒ Failed to parse response string:", e);
2062
+ }
2063
+ }
2064
+ }
2065
+ // Extract combined signature from LIT SDK result
2066
+ // LIT SDK returns signatures in result.signatures.btcTxSig after combination
2067
+ let combinedSignature;
2068
+ if (result.signatures && typeof result.signatures === 'object') {
2069
+ const btcTxSig = result.signatures.btcTxSig;
2070
+ if (btcTxSig && btcTxSig.signature) {
2071
+ // LIT SDK combined signature
2072
+ combinedSignature = btcTxSig.signature;
2073
+ if (this.config.debug && combinedSignature) {
2074
+ console.log("āœ… Extracted combined signature from LIT SDK:", {
2075
+ signatureLength: combinedSignature.length,
2076
+ signatureStart: combinedSignature.substring(0, 20) + "..."
2077
+ });
2078
+ }
2079
+ }
2080
+ }
2081
+ // Return standardized response
2082
+ return {
2083
+ success: responseData?.success ?? false,
2084
+ unsignedTxHex: responseData?.unsignedTxHex,
2085
+ sigHash: responseData?.sigHash,
2086
+ signature: combinedSignature || responseData?.signature,
2087
+ pkpPublicKey: responseData?.pkpPublicKey,
2088
+ pkpBtcAddress: responseData?.pkpBtcAddress,
2089
+ destination: responseData?.destination,
2090
+ userReceivesAmount: responseData?.userReceivesAmount,
2091
+ networkFee: responseData?.networkFee,
2092
+ changeAmount: responseData?.changeAmount,
2093
+ utxo: responseData?.utxo,
2094
+ authorization: responseData?.authorization,
2095
+ timestamp: responseData?.timestamp,
2096
+ action: responseData?.action,
2097
+ error: result.error || responseData?.error,
2098
+ failedStep: responseData?.failedStep,
2099
+ };
2100
+ }
1517
2101
  /**
1518
2102
  * Get trustless BTC price from Price Oracle LIT Action
1519
2103
  *
@@ -1530,7 +2114,9 @@ class LitOps {
1530
2114
  // Get LIT Action info from registry
1531
2115
  const litActions = (this.config.network === "datil"
1532
2116
  ? dh_lit_actions_1.DH_LIT_ACTIONS_DATIL
1533
- : dh_lit_actions_1.DH_LIT_ACTIONS_DATIL_TEST);
2117
+ : (() => {
2118
+ throw new Error("Unsupported LIT network");
2119
+ })());
1534
2120
  console.log("litActions in getActions", litActions);
1535
2121
  const litActionInfo = litActions.priceOracle;
1536
2122
  if (!litActionInfo || !litActionInfo.cid) {