@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.
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/interfaces/chunks/lit-action-execution.d.ts +11 -0
- package/dist/interfaces/chunks/lit-action-execution.d.ts.map +1 -1
- package/dist/modules/action-executor.module.d.ts.map +1 -1
- package/dist/modules/action-executor.module.js +3 -0
- 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 +3 -0
- package/dist/modules/auth-manager.module.js.map +1 -1
- package/dist/modules/client-manager.module.d.ts.map +1 -1
- package/dist/modules/client-manager.module.js.map +1 -1
- package/dist/modules/lit-ops.module.d.ts +159 -0
- package/dist/modules/lit-ops.module.d.ts.map +1 -1
- package/dist/modules/lit-ops.module.js +623 -37
- package/dist/modules/lit-ops.module.js.map +1 -1
- package/dist/modules/pkp-macros.module.d.ts +4 -0
- package/dist/modules/pkp-macros.module.d.ts.map +1 -1
- package/dist/modules/pkp-macros.module.js +28 -8
- package/dist/modules/pkp-macros.module.js.map +1 -1
- package/package.json +2 -2
|
@@ -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
|
-
:
|
|
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:
|
|
658
|
-
//
|
|
659
|
-
//
|
|
660
|
-
//
|
|
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, //
|
|
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
|
|
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
|
-
:
|
|
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
|
|
1247
|
+
const registry = selectedNetwork === "datil"
|
|
1262
1248
|
? dh_lit_actions_1.DH_LIT_ACTIONS_DATIL
|
|
1263
|
-
:
|
|
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 -
|
|
1266
|
-
return this.createAndValidatePkpToLitAction(
|
|
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
|
-
:
|
|
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-
|
|
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
|
-
:
|
|
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) {
|