@gvnrdao/dh-sdk 0.0.304 → 0.0.306

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.js CHANGED
@@ -438,9 +438,13 @@ var init_deployment_addresses = __esm({
438
438
  reason: "Validator gas fix (#420): BitcoinAddressValidator packed-table lookups; VERSION 1.0.0 -> 1.0.1"
439
439
  },
440
440
  UCDController: {
441
+ previousImplementation: "0x16f94AcC78cE87bEeBCfF90552091B3EfC071E48",
441
442
  newImplementation: "0x28B8cAB89D89B3F83581FD2290de2Ce84535bd0A",
442
- upgradedBy: "Reconciled from chain \u2014 Upgraded event log unavailable; provenance omitted (never fabricated)",
443
- reason: "Reconciled from chain \u2014 mainnet audit rollout batch (cross-ref onchain-auth/.safe-batches/mainnet-audit-execute.json)"
443
+ upgradedAt: "2026-07-06T10:41:59.000Z",
444
+ upgradedBy: "AdminModule/Safe audit-batch upgradeToAndCall; executed by 0xEba7BfAeB35ee18408b424Ee0BB45AdDf776589f in tx 0xf6609d3fa43b460d953c85d8d7265b59bf177723042db79a6a700571bad777b7 (block 25472962)",
445
+ reason: "Reconciled from chain \u2014 mainnet audit rollout batch (cross-ref onchain-auth/.safe-batches/mainnet-audit-execute.json)",
446
+ executeTx: "0xf6609d3fa43b460d953c85d8d7265b59bf177723042db79a6a700571bad777b7",
447
+ block: 25472962
444
448
  },
445
449
  PositionManagerCoreModule: {
446
450
  previousImplementation: "0x6C8b0FB93F8d0239254aefaC24d4264cA2F8AAeB",
@@ -567,45 +571,47 @@ var init_deployment_addresses = __esm({
567
571
  };
568
572
  LOCALHOST_DEPLOYMENT = {
569
573
  network: "localhost",
570
- chainId: 31337,
571
- timestamp: "2026-06-11T12:30:59.589Z",
574
+ chainId: 1337,
575
+ timestamp: "2026-07-20T19:45:58.514Z",
572
576
  deployer: "",
573
577
  contracts: {
574
- MessageHashBuilder: "0x1613beB3B2C4f22Ee086B2b38C1476A3cE7f78E8",
575
- UpgradeValidator: "0x610178dA211FEF7D417bC0e6FeD39F05609AD788",
578
+ MessageHashBuilder: "0xa82fF9aFd8f496c3d6ac40E2a0F282E47488CFc9",
579
+ LITActionValidator: "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853",
580
+ UpgradeValidator: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318",
576
581
  UCDToken: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512",
577
582
  UCDController: "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9",
578
- PositionManagerCoreModule: "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0",
579
- TermManagerModule: "0x9A676e781A523b5d0C0e43731313A708CB607508",
580
- LoanOperationsManagerModule: "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c",
581
- BTCSpendAuthorizer: "0x59b670e9fA9D0A427751Af201D676719a970857b",
582
- CollateralManagerModule: "0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f",
583
- LiquidationManagerModule: "0x7a2088a1bFc9d81c55368AE168C2C02570cB814F",
584
- CircuitBreakerModule: "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1",
585
- AdminModule: "0xc5a5C42992dECbae36851359345FE25997F5C42d",
586
- PositionManagerViews: "0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE",
587
- PositionManager: "0xf5059a5D33d5853360D16C683c16e67980206f36",
588
- OperationAuthorizationRegistry: "0xF8e31cb472bc70500f08Cd84917E5A1912Ec8397",
589
- PKPValidation: "0xc0F115A19107322cFBf1cDBC7ea011C19EbDB4F8"
583
+ PositionManagerCoreModule: "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e",
584
+ TermManagerModule: "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82",
585
+ LoanOperationsManagerModule: "0x68B1D87F95878fE05B998F19b66F4baba5De1aed",
586
+ BTCSpendAuthorizer: "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d",
587
+ CollateralManagerModule: "0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44",
588
+ LiquidationManagerModule: "0x4A679253410272dd5232B3Ff7cF5dbB88f295319",
589
+ CircuitBreakerModule: "0x0B306BF915C4d645ff596e518fAf3F9669b97016",
590
+ AdminModule: "0x09635F643e140090A9A8Dcd712eD6285858ceBef",
591
+ PositionManagerViews: "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1",
592
+ PositionManager: "0x851356ae760d987E095750cCeb3bC6014560891C",
593
+ OperationAuthorizationRegistry: "0xc96304e3c037f81dA488ed9dEa1D8F2a48278a75",
594
+ PKPValidation: "0xD0141E899a65C95a556fE2B27e5982A6DE7fDD7A"
590
595
  }
591
596
  };
592
597
  LOCALHOST_CONTRACTS = {
593
- MessageHashBuilder: "0x1613beB3B2C4f22Ee086B2b38C1476A3cE7f78E8",
594
- UpgradeValidator: "0x610178dA211FEF7D417bC0e6FeD39F05609AD788",
598
+ MessageHashBuilder: "0xa82fF9aFd8f496c3d6ac40E2a0F282E47488CFc9",
599
+ LITActionValidator: "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853",
600
+ UpgradeValidator: "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318",
595
601
  UCDToken: "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512",
596
602
  UCDController: "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9",
597
- PositionManagerCoreModule: "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0",
598
- TermManagerModule: "0x9A676e781A523b5d0C0e43731313A708CB607508",
599
- LoanOperationsManagerModule: "0x3Aa5ebB10DC797CAC828524e59A333d0A371443c",
600
- BTCSpendAuthorizer: "0x59b670e9fA9D0A427751Af201D676719a970857b",
601
- CollateralManagerModule: "0xa85233C63b9Ee964Add6F2cffe00Fd84eb32338f",
602
- LiquidationManagerModule: "0x7a2088a1bFc9d81c55368AE168C2C02570cB814F",
603
- CircuitBreakerModule: "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1",
604
- AdminModule: "0xc5a5C42992dECbae36851359345FE25997F5C42d",
605
- PositionManagerViews: "0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE",
606
- PositionManager: "0xf5059a5D33d5853360D16C683c16e67980206f36",
607
- OperationAuthorizationRegistry: "0xF8e31cb472bc70500f08Cd84917E5A1912Ec8397",
608
- PKPValidation: "0xc0F115A19107322cFBf1cDBC7ea011C19EbDB4F8"
603
+ PositionManagerCoreModule: "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e",
604
+ TermManagerModule: "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82",
605
+ LoanOperationsManagerModule: "0x68B1D87F95878fE05B998F19b66F4baba5De1aed",
606
+ BTCSpendAuthorizer: "0xc6e7DF5E7b4f2A278906862b61205850344D4e7d",
607
+ CollateralManagerModule: "0x322813Fd9A801c5507c9de605d63CEA4f2CE6c44",
608
+ LiquidationManagerModule: "0x4A679253410272dd5232B3Ff7cF5dbB88f295319",
609
+ CircuitBreakerModule: "0x0B306BF915C4d645ff596e518fAf3F9669b97016",
610
+ AdminModule: "0x09635F643e140090A9A8Dcd712eD6285858ceBef",
611
+ PositionManagerViews: "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1",
612
+ PositionManager: "0x851356ae760d987E095750cCeb3bC6014560891C",
613
+ OperationAuthorizationRegistry: "0xc96304e3c037f81dA488ed9dEa1D8F2a48278a75",
614
+ PKPValidation: "0xD0141E899a65C95a556fE2B27e5982A6DE7fDD7A"
609
615
  };
610
616
  ALL_DEPLOYMENTS = {
611
617
  sepolia: SEPOLIA_DEPLOYMENT,
@@ -1287,7 +1293,7 @@ var require_pkg_src = __commonJS({
1287
1293
  description: "Production Pkp Validator",
1288
1294
  version: "1.0.0",
1289
1295
  deployed: true,
1290
- deployedAt: 1783106284785,
1296
+ deployedAt: 1784569687492,
1291
1297
  size: 4140,
1292
1298
  hash: "4c0d65bf1f33cdac22a78fd8c4764319cc3fe00650e0fe7fa8a6090d9a318a7b",
1293
1299
  validatorWalletAddress: "0x82db9f515957aa380b596c6ea2bd30cef181f236",
@@ -1364,17 +1370,17 @@ var require_pkg_src = __commonJS({
1364
1370
  }
1365
1371
  },
1366
1372
  btcWithdrawal: {
1367
- cid: "QmYG1o9qMBZsEMDE9DNsJMzQmvxfj6jTu9V37WwuJZAtC2",
1373
+ cid: "QmexvpfHPacjsVcqNHHLyJhSnnAPLgbWmWd9N3NDLDvYds",
1368
1374
  authorizedCidHex: cidToHex(
1369
- "QmYG1o9qMBZsEMDE9DNsJMzQmvxfj6jTu9V37WwuJZAtC2"
1375
+ "QmexvpfHPacjsVcqNHHLyJhSnnAPLgbWmWd9N3NDLDvYds"
1370
1376
  ),
1371
1377
  name: "Btc Withdrawal",
1372
1378
  description: "Production Btc Withdrawal",
1373
- version: "1.2.1",
1379
+ version: "1.2.3",
1374
1380
  deployed: true,
1375
- deployedAt: 1784316549409,
1376
- size: 90692,
1377
- hash: "ca7276763142fe1fc812b70f6319973000faf338a91c531f898f8f6406035c64",
1381
+ deployedAt: 1784585746901,
1382
+ size: 92027,
1383
+ hash: "7b4f4eab1f0c08b8b5b1c9cdb1064dd403ec13f57765919f62dec67fb8ba3c69",
1378
1384
  validatorWalletAddress: "0x82DB9F515957aA380B596C6eA2Bd30CEF181f236",
1379
1385
  pkp: {
1380
1386
  publicKey: "0x043616787c5432415c24378c4ef48de2bcd6bb7b575b837e3cff09171802662da7105d79586c7659677a0ecbaddac4cce06cb2a11f69a16fa0c4d7002ac7d51a4d",
@@ -3746,12 +3752,23 @@ ${auth.clientId}`;
3746
3752
  if (!data.vout || !Array.isArray(data.vout)) {
3747
3753
  return null;
3748
3754
  }
3749
- return data.vout.map((output, index) => ({
3750
- index,
3751
- scriptpubkey: output.scriptpubkey,
3752
- scriptpubkey_address: output.scriptpubkey_address,
3753
- value: output.value ?? 0
3754
- }));
3755
+ return data.vout.map((output, index) => {
3756
+ if (output.value === void 0) {
3757
+ throw new Error(
3758
+ `getTransactionOutputs(${txid}): output ${index} is missing its value \u2014 malformed provider response, refusing to return outputs that cannot be value-verified`
3759
+ );
3760
+ }
3761
+ assertSaneSatoshis(
3762
+ output.value,
3763
+ `getTransactionOutputs(${txid}) output ${index}`
3764
+ );
3765
+ return {
3766
+ index,
3767
+ scriptpubkey: output.scriptpubkey,
3768
+ scriptpubkey_address: output.scriptpubkey_address,
3769
+ value: output.value
3770
+ };
3771
+ });
3755
3772
  } catch (error) {
3756
3773
  clearTimeout(timeoutId);
3757
3774
  if (isAbortError(error)) {
@@ -5513,7 +5530,12 @@ var init_network_configs = __esm({
5513
5530
  NETWORK_CONFIGS = {
5514
5531
  1: getMainnetConfig(),
5515
5532
  11155111: getSepoliaConfig(),
5516
- 1337: getLocalhostConfig()
5533
+ 1337: getLocalhostConfig(),
5534
+ // In-process hardhat default chainId — same localhost deployment as 1337
5535
+ // (`npx hardhat node`), so consumers on either local chain resolve config.
5536
+ // chainId overridden so the resolved config self-describes the chain that
5537
+ // was actually looked up (downstream bind/log/validate reads it).
5538
+ 31337: { ...getLocalhostConfig(), chainId: 31337 }
5517
5539
  };
5518
5540
  DEFAULT_NETWORK_CONFIG = {
5519
5541
  /** Fallback when chain is unknown — production Chipotle. */
@@ -6935,12 +6957,20 @@ async function assertSafeQuantumSubmission(opts) {
6935
6957
  ...opts.sleep ? { sleep: opts.sleep } : {}
6936
6958
  };
6937
6959
  await awaitSafeSubmissionWindow(quantumTimestamp, gateOpts);
6960
+ const SAME_BLOCK_INTERACTION_SELECTOR = "0x3b53d1db";
6961
+ const laneGuardActive = opts.laneGuardActive === true;
6938
6962
  for (let sim = 1; ; sim++) {
6939
6963
  try {
6940
6964
  await provider.call({ to, from, data });
6941
6965
  break;
6942
6966
  } catch (simError) {
6943
6967
  const decoded = decodeQuantumRevert(simError);
6968
+ if (laneGuardActive && decoded.selector === SAME_BLOCK_INTERACTION_SELECTOR) {
6969
+ onDebug(
6970
+ "\u21AA\uFE0F [lane-only] Simulated SameBlockInteraction is a stale-latest-block artifact (the simulated block contains this flow's own previous tx) \u2014 proceeding to broadcast; the on-chain guard stays authoritative"
6971
+ );
6972
+ break;
6973
+ }
6944
6974
  if (decoded.selector === DEAD_ZONE_VIOLATION_SELECTOR && sim <= maxResimulations) {
6945
6975
  const sigQuantum = Math.floor(quantumTimestamp / QUANTUM_WINDOW_SECONDS) * QUANTUM_WINDOW_SECONDS;
6946
6976
  const realCurrentQuantum = Math.floor(now() / QUANTUM_WINDOW_SECONDS) * QUANTUM_WINDOW_SECONDS;
@@ -6976,6 +7006,28 @@ async function assertSafeQuantumSubmission(opts) {
6976
7006
  await awaitSafeSubmissionWindow(quantumTimestamp, gateOpts);
6977
7007
  }
6978
7008
 
7009
+ // src/utils/lane-guard.utils.ts
7010
+ var HARDHAT_CHAIN_IDS = /* @__PURE__ */ new Set([1337, 31337]);
7011
+ function laneGuardEnvEnabled() {
7012
+ return typeof process !== "undefined" && process.env?.LIT_LANE_GUARD === "1";
7013
+ }
7014
+ async function isLaneGuardActiveOnProvider(provider) {
7015
+ if (!laneGuardEnvEnabled())
7016
+ return false;
7017
+ if (!provider || typeof provider.send !== "function")
7018
+ return false;
7019
+ try {
7020
+ const [chainIdHex, clientVersion] = await Promise.all([
7021
+ provider.send("eth_chainId", []),
7022
+ provider.send("web3_clientVersion", [])
7023
+ ]);
7024
+ const chainId = Number(chainIdHex);
7025
+ return HARDHAT_CHAIN_IDS.has(chainId) && typeof clientVersion === "string" && clientVersion.toLowerCase().includes("hardhat");
7026
+ } catch {
7027
+ return false;
7028
+ }
7029
+ }
7030
+
6979
7031
  // src/utils/btc-withdrawal-message.ts
6980
7032
  var import_ethers6 = require("ethers");
6981
7033
  var QUANTUM_SECONDS = 60;
@@ -16318,6 +16370,10 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
16318
16370
  this.litOps = new import_dh_lit_ops.LitOps({
16319
16371
  mode: config.mode || "standalone",
16320
16372
  network: config.litNetwork || DEFAULT_LIT_NETWORK,
16373
+ // Completes the module's chainId resolution chain (jsParams shapes →
16374
+ // config.chainId) — e.g. the lane validator-override chain binding
16375
+ // reads it when a jsParams shape lacks chainId.
16376
+ chainId: config.chainId,
16321
16377
  signer: config.mode === "standalone" ? config.litOpsSigner : void 0,
16322
16378
  serviceEndpoint: isServiceModeConfig(config) ? config.serviceEndpoint : void 0,
16323
16379
  // Hand lit-ops a session-aware auth getter so every request it makes
@@ -16995,6 +17051,19 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
16995
17051
  }
16996
17052
  const MAX_FULL_RETRIES = 3;
16997
17053
  for (let fullRetry = 1; fullRetry <= MAX_FULL_RETRIES; fullRetry++) {
17054
+ if (await this.isLocalLaneGuardActive()) {
17055
+ const phase = Math.floor(Date.now() / 1e3) % 60;
17056
+ if (phase > 30) {
17057
+ const waitMs = (60 - phase + 1) * 1e3;
17058
+ if (this.config.debug) {
17059
+ log.info(
17060
+ `\u23F3 Quantum-phase alignment (lane-only): ${phase}s into the quantum \u2014 waiting ${Math.ceil(waitMs / 1e3)}s for the next boundary before authorization`,
17061
+ {}
17062
+ );
17063
+ }
17064
+ await new Promise((resolve) => setTimeout(resolve, waitMs));
17065
+ }
17066
+ }
16998
17067
  if (fullRetry > 1 && this.config.debug) {
16999
17068
  log.info(
17000
17069
  `\u{1F504} Full mint retry ${fullRetry}/${MAX_FULL_RETRIES} due to timestamp staleness...`,
@@ -17743,6 +17812,7 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
17743
17812
  from: fromAddress,
17744
17813
  data: mintCalldata,
17745
17814
  quantumTimestamp: Number(validationResponse.timestamp),
17815
+ laneGuardActive: await this.isLocalLaneGuardActive(),
17746
17816
  onDebug: this.config.debug ? (msg) => log.info(msg, {}) : void 0
17747
17817
  });
17748
17818
  } catch (simError) {
@@ -19038,6 +19108,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
19038
19108
  from: await extendSigner.getAddress(),
19039
19109
  data: extendCalldata,
19040
19110
  quantumTimestamp: Number(quantumTimestamp),
19111
+ laneGuardActive: await this.isLocalLaneGuardActive(),
19041
19112
  onDebug: this.config.debug ? (msg) => log.info(msg, {}) : void 0
19042
19113
  });
19043
19114
  } catch (simError) {
@@ -19938,6 +20009,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
19938
20009
  from: paymentFrom,
19939
20010
  data: paymentCalldata,
19940
20011
  quantumTimestamp: Number(quantumTimestamp),
20012
+ laneGuardActive: await this.isLocalLaneGuardActive(),
19941
20013
  onDebug: this.config.debug ? (msg) => log.info(msg, {}) : void 0
19942
20014
  });
19943
20015
  } catch (simError) {
@@ -20677,6 +20749,7 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
20677
20749
  from: await withdrawSigner.getAddress(),
20678
20750
  data: withdrawCalldata,
20679
20751
  quantumTimestamp: Number(withdrawalParams.quantumTimestamp),
20752
+ laneGuardActive: await this.isLocalLaneGuardActive(),
20680
20753
  onDebug: this.config.debug ? (msg) => log.info(msg, {}) : void 0
20681
20754
  });
20682
20755
  tx = await sendEip1559Transaction({
@@ -20754,7 +20827,9 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
20754
20827
  gasUsed: receipt.gasUsed?.toString() || "unknown",
20755
20828
  utxoTxid: validationResponse.utxoTxid,
20756
20829
  utxoVout: validationResponse.utxoVout,
20757
- utxoSatoshis: validationResponse.utxoSatoshis
20830
+ utxoSatoshis: validationResponse.utxoSatoshis,
20831
+ // Phase B: full consensus-validated spend set (absent on older actions).
20832
+ confirmedUtxos: validationResponse.confirmedUtxos
20758
20833
  };
20759
20834
  } catch (error) {
20760
20835
  const errorMsg = error instanceof Error ? error.message : String(error);
@@ -20829,15 +20904,180 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
20829
20904
  * @param request - Execution request with positionId, utxoIdentifier, and networkFee
20830
20905
  * @returns Execution result with Bitcoin txid
20831
20906
  */
20832
- async executeBTCWithdrawal(request) {
20833
- this.ensureInitialized();
20834
- if (this.config.mode !== "service") {
20907
+ /**
20908
+ * STANDALONE Phase 2: sign + broadcast the withdrawal Bitcoin transaction
20909
+ * in-process the same orchestration lit-ops-server performs, composed
20910
+ * from the same primitives (`litOps.signBTCTransaction`, which has always
20911
+ * had a standalone path, and `broadcastSignedBitcoinTransaction`).
20912
+ * Both modes must support withdrawal execution (Master mandate 2026-07-21).
20913
+ *
20914
+ * The service path's post-broadcast CRIT-2 re-verification exists to catch
20915
+ * a LYING SERVER; here the broadcast happens locally from the signatures we
20916
+ * just obtained, so the esplora-returned txid is already first-hand.
20917
+ */
20918
+ async executeBTCWithdrawalStandalonePhase2(request, envelope, txid, vout, chainId) {
20919
+ const positionDetails = await this.getPositionDetailsView(
20920
+ request.positionId
20921
+ );
20922
+ if (!positionDetails) {
20923
+ return { success: false, error: `Position ${request.positionId} not found` };
20924
+ }
20925
+ const pkpId = positionDetails.pkpId;
20926
+ const vaultAddress = positionDetails.vaultAddress;
20927
+ if (!pkpId || pkpId === import_ethers14.ZeroHash) {
20928
+ return { success: false, error: "Position has no PKP" };
20929
+ }
20930
+ if (!vaultAddress) {
20931
+ return { success: false, error: "Position has no vault address" };
20932
+ }
20933
+ const pkpCache = this.cacheManager.getCache("pkp-data", {
20934
+ maxSize: 500,
20935
+ ttlMs: 24 * 60 * 60 * 1e3
20936
+ });
20937
+ let publicKey = pkpCache.get(request.positionId)?.publicKey;
20938
+ if (!publicKey) {
20939
+ const derived = await this.litOps.deriveDiamondHandsLoanPkpPublicKey({
20940
+ pkpId
20941
+ });
20942
+ publicKey = derived.publicKey;
20943
+ }
20944
+ if (!publicKey) {
20945
+ return { success: false, error: "Failed to resolve PKP public key" };
20946
+ }
20947
+ const chipotlePkpAddress = (0, import_ethers14.computeAddress)(publicKey);
20948
+ const STANDALONE_CHAIN_NAMES = {
20949
+ 1: "ethereum",
20950
+ 11155111: "sepolia",
20951
+ 1337: "hardhat",
20952
+ 31337: "hardhat"
20953
+ };
20954
+ const chainName = STANDALONE_CHAIN_NAMES[chainId];
20955
+ if (!chainName) {
20835
20956
  return {
20836
20957
  success: false,
20837
- error: "BTC withdrawal Phase 2 requires service mode. Set sdkConfig.mode = 'service' and serviceEndpoint to a lit-ops-server."
20958
+ error: `Unsupported chainId ${chainId} for standalone BTC withdrawal (supported: 1, 11155111, 1337, 31337)`
20838
20959
  };
20839
20960
  }
20840
- if (!this.config.serviceEndpoint) {
20961
+ const bitcoinNetworkName = chainId === 1 ? "mainnet" : "regtest";
20962
+ const bitcoin = await import("bitcoinjs-lib");
20963
+ const bitcoinNetwork = chainId === 1 ? bitcoin.networks.bitcoin : chainId === 1337 || chainId === 31337 ? bitcoin.networks.regtest : bitcoin.networks.testnet;
20964
+ let scriptPubKeyBuffer;
20965
+ if (vaultAddress.startsWith("bcrt1q")) {
20966
+ const bech322 = await import("bech32");
20967
+ const decoded = bech322.bech32.decode(vaultAddress);
20968
+ const witnessProgram = Buffer.from(
20969
+ bech322.bech32.fromWords(decoded.words.slice(1))
20970
+ );
20971
+ if (witnessProgram.length !== 20) {
20972
+ return {
20973
+ success: false,
20974
+ error: `Vault address ${vaultAddress} decodes to a ${witnessProgram.length}-byte witness program \u2014 expected 20-byte P2WPKH`
20975
+ };
20976
+ }
20977
+ scriptPubKeyBuffer = Buffer.concat([
20978
+ Buffer.from([0, witnessProgram.length]),
20979
+ witnessProgram
20980
+ ]);
20981
+ } else {
20982
+ scriptPubKeyBuffer = bitcoin.address.toOutputScript(
20983
+ vaultAddress,
20984
+ bitcoinNetwork
20985
+ );
20986
+ }
20987
+ const scriptPubKey = scriptPubKeyBuffer.toString("hex");
20988
+ const executionUtxos = (envelope.utxos && envelope.utxos.length ? envelope.utxos : [{ txid, vout, value: request.utxoSatoshis }]).map((u) => ({ ...u, scriptPubKey }));
20989
+ const dc = this.config.contractAddresses || {};
20990
+ const signerContractAddresses = {
20991
+ LoanOperationsManagerModule: dc.loanOperationsManager ?? "",
20992
+ PositionManager: dc.positionManager ?? "",
20993
+ BTCSpendAuthorizer: dc.btcSpendAuthorizer ?? "",
20994
+ PositionDelegateRegistry: dc.positionDelegateRegistry ?? "",
20995
+ OperationAuthorizationRegistry: dc.operationAuthorizationRegistry ?? "",
20996
+ ...dc.bitcoinProviderRegistry ? { BitcoinProviderRegistry: dc.bitcoinProviderRegistry } : {}
20997
+ };
20998
+ const signResult = await this.litOps.signBTCTransaction({
20999
+ auth: {
21000
+ positionId: envelope.positionId,
21001
+ utxo: { txid, vout, value: request.utxoSatoshis, scriptPubKey },
21002
+ utxos: executionUtxos,
21003
+ networkFee: envelope.networkFee,
21004
+ targetAddress: envelope.targetAddress,
21005
+ targetAmount: envelope.targetAmount,
21006
+ timestamp: envelope.timestamp,
21007
+ signature: envelope.userSignature,
21008
+ chainId
21009
+ },
21010
+ publicKey,
21011
+ pkpId: chipotlePkpAddress,
21012
+ chain: chainName,
21013
+ bitcoinNetwork: bitcoinNetworkName,
21014
+ rpcUrl: this.config.ethRpcUrl,
21015
+ contractAddresses: signerContractAddresses
21016
+ });
21017
+ if (!signResult.success) {
21018
+ return {
21019
+ success: false,
21020
+ error: signResult.error ?? "BTC transaction signing failed"
21021
+ };
21022
+ }
21023
+ if (!signResult.unsignedTxHex || !signResult.signatures?.length) {
21024
+ return {
21025
+ success: false,
21026
+ error: "BTC signing returned incomplete data (missing unsignedTxHex/signatures)"
21027
+ };
21028
+ }
21029
+ if (!signResult.userReceivesAmount) {
21030
+ return { success: false, error: "BTC signing did not return userReceivesAmount" };
21031
+ }
21032
+ const broadcastUrl = this.config.bitcoinProviders?.[0]?.url;
21033
+ if (!broadcastUrl) {
21034
+ return {
21035
+ success: false,
21036
+ error: "Standalone Phase 2 broadcast requires config.bitcoinProviders[0].url (esplora base)"
21037
+ };
21038
+ }
21039
+ try {
21040
+ const { txid: btcTxid } = await (0, import_dh_lit_ops.broadcastSignedBitcoinTransaction)({
21041
+ signatures: signResult.signatures,
21042
+ utxos: executionUtxos,
21043
+ pkpPublicKey: signResult.pkpPublicKey ?? publicKey,
21044
+ destination: envelope.targetAddress,
21045
+ userReceivesAmount: signResult.userReceivesAmount,
21046
+ changeAmount: signResult.changeAmount,
21047
+ pkpBtcAddress: signResult.pkpBtcAddress,
21048
+ bitcoinNetwork: bitcoinNetworkName,
21049
+ bitcoinRpcUrl: broadcastUrl,
21050
+ ...this.config.debug ? {
21051
+ debug: (level, msg, data) => {
21052
+ if (level === "warn")
21053
+ log.warn(msg, { data });
21054
+ else if (level === "error")
21055
+ log.error(msg, { data });
21056
+ else
21057
+ log.info(msg, { data });
21058
+ }
21059
+ } : {}
21060
+ });
21061
+ if (this.config.debug) {
21062
+ log.info("\u2705 Standalone Phase 2 broadcast successful", { txid: btcTxid });
21063
+ }
21064
+ return {
21065
+ success: true,
21066
+ txid: btcTxid,
21067
+ amountSent: signResult.userReceivesAmount,
21068
+ networkFee: signResult.networkFee,
21069
+ destination: envelope.targetAddress
21070
+ };
21071
+ } catch (broadcastError) {
21072
+ return {
21073
+ success: false,
21074
+ error: `BTC broadcast failed: ${broadcastError instanceof Error ? broadcastError.message : String(broadcastError)}`
21075
+ };
21076
+ }
21077
+ }
21078
+ async executeBTCWithdrawal(request) {
21079
+ this.ensureInitialized();
21080
+ if (this.config.mode === "service" && !this.config.serviceEndpoint) {
20841
21081
  return { success: false, error: "serviceEndpoint required for BTC withdrawal" };
20842
21082
  }
20843
21083
  if (!request.positionId) {
@@ -20892,6 +21132,15 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
20892
21132
  signer,
20893
21133
  ...request.utxos ? { utxos: request.utxos } : {}
20894
21134
  });
21135
+ if (this.config.mode !== "service") {
21136
+ return await this.executeBTCWithdrawalStandalonePhase2(
21137
+ request,
21138
+ envelope,
21139
+ txid,
21140
+ vout,
21141
+ chainId
21142
+ );
21143
+ }
20895
21144
  const headers = {
20896
21145
  "Content-Type": "application/json",
20897
21146
  ...await this.getAuthHeader()
@@ -21437,7 +21686,12 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
21437
21686
  log.info("\u{1F50D} Found vault UTXO for execution", { utxoIdentifier });
21438
21687
  }
21439
21688
  let executionUtxos;
21440
- const gatheredUtxos = await this.fetchConfirmedVaultUtxos(positionId);
21689
+ const gatheredUtxos = authResult.confirmedUtxos && authResult.confirmedUtxos.length > 0 ? authResult.confirmedUtxos.map((u) => ({
21690
+ txid: u.txid,
21691
+ vout: Number(u.vout),
21692
+ value: Number(u.value),
21693
+ confirmations: 0
21694
+ })) : await this.fetchConfirmedVaultUtxos(positionId);
21441
21695
  if (gatheredUtxos.length > 0) {
21442
21696
  const normTxid = (t) => String(t).toLowerCase().replace(/^0x/, "");
21443
21697
  const byOutpoint = /* @__PURE__ */ new Map();
@@ -22204,6 +22458,25 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
22204
22458
  const chain = this.config.chain?.toLowerCase() || "";
22205
22459
  return chain.includes("mainnet");
22206
22460
  }
22461
+ /**
22462
+ * Local-lane activation, verified against the LIVE node at call time (not
22463
+ * the chainId cached at init — a provider that switched networks after
22464
+ * init fails the fresh probe). Zero RPC cost outside a lane process tree:
22465
+ * without LIT_LANE_GUARD=1 this short-circuits to false before any probe.
22466
+ */
22467
+ async isLocalLaneGuardActive() {
22468
+ if (!laneGuardEnvEnabled())
22469
+ return false;
22470
+ let provider;
22471
+ try {
22472
+ provider = this.config.provider ?? this.getProviderOrThrow();
22473
+ } catch {
22474
+ return false;
22475
+ }
22476
+ return isLaneGuardActiveOnProvider(
22477
+ provider
22478
+ );
22479
+ }
22207
22480
  /**
22208
22481
  * Get Bitcoin network based on chain.
22209
22482
  *