@gvnrdao/dh-sdk 0.0.313 → 0.0.315

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
@@ -1310,30 +1310,30 @@ var require_pkg_src = __commonJS({
1310
1310
  }
1311
1311
  },
1312
1312
  btcTransactionSigner: {
1313
- cid: "QmZFzjpdwpiBxHPv3t1mhjv8hfPRD1hPZGJ7jUU9w6V2Ca",
1313
+ cid: "QmPncBUbxN9giWntJcvBMFW9GDAgA3DwgAkUAHxSsY67ic",
1314
1314
  authorizedCidHex: cidToHex(
1315
- "QmZFzjpdwpiBxHPv3t1mhjv8hfPRD1hPZGJ7jUU9w6V2Ca"
1315
+ "QmPncBUbxN9giWntJcvBMFW9GDAgA3DwgAkUAHxSsY67ic"
1316
1316
  ),
1317
1317
  name: "Btc Transaction Signer",
1318
1318
  description: "Production Btc Transaction Signer",
1319
1319
  version: "1.1.1",
1320
1320
  deployed: true,
1321
- deployedAt: 1785173232972,
1322
- size: 66562,
1323
- hash: "13639ec13bfed381c3c9d81e17e37917446ba30d04d4d8e45809a6868139c3cb"
1321
+ deployedAt: 1785226367707,
1322
+ size: 66624,
1323
+ hash: "9e0d9909519d5133bab03a9491566870b08d8b42c80e2d768bd24f02946cc781"
1324
1324
  },
1325
1325
  ucdMintValidator: {
1326
- cid: "Qmb1TPCaNYRTHsnhZrE1J4BtVYNWBnWSneXRqyAco1XKku",
1326
+ cid: "QmPRLCfseSWCAS4PpvQWt9aEd6rXqWYG4JyGTn26KYk6xc",
1327
1327
  authorizedCidHex: cidToHex(
1328
- "Qmb1TPCaNYRTHsnhZrE1J4BtVYNWBnWSneXRqyAco1XKku"
1328
+ "QmPRLCfseSWCAS4PpvQWt9aEd6rXqWYG4JyGTn26KYk6xc"
1329
1329
  ),
1330
1330
  name: "Ucd Mint Validator",
1331
1331
  description: "Production Ucd Mint Validator",
1332
1332
  version: "1.2.1",
1333
1333
  deployed: true,
1334
- deployedAt: 1785173240530,
1335
- size: 81596,
1336
- hash: "fdaa7abb4ad28ae1f20f5cd6e3e03e5a8787fd6ac05938f51070ed16844f80f5",
1334
+ deployedAt: 1785226381631,
1335
+ size: 81658,
1336
+ hash: "d8ea21622885c3d26fdb64e2ba9d2f9460753a5cd7934b2928858899537443eb",
1337
1337
  validatorWalletAddress: "0x82DB9F515957aA380B596C6eA2Bd30CEF181f236",
1338
1338
  pkp: {
1339
1339
  publicKey: "0x041ab17cd91fc5c0b761eea6092d032807561b621b82c488826776e04a9158d61ba64d809a4729f0501289d980732cb06d8dfd06999dd9c8efd2f495dad78b31bb",
@@ -1341,17 +1341,17 @@ var require_pkg_src = __commonJS({
1341
1341
  }
1342
1342
  },
1343
1343
  processPaymentValidator: {
1344
- cid: "QmWSSAgmLtfVsRawHU2Uf72Xw4hM5T5Jcx2n7EVmEHQD1E",
1344
+ cid: "QmNUzmHQHsaKThGkfZiD3xZrN64qZfn4P6J4MqWgvkeEsX",
1345
1345
  authorizedCidHex: cidToHex(
1346
- "QmWSSAgmLtfVsRawHU2Uf72Xw4hM5T5Jcx2n7EVmEHQD1E"
1346
+ "QmNUzmHQHsaKThGkfZiD3xZrN64qZfn4P6J4MqWgvkeEsX"
1347
1347
  ),
1348
1348
  name: "Process Payment Validator",
1349
1349
  description: "Production Process Payment Validator",
1350
1350
  version: "1.2.1",
1351
1351
  deployed: true,
1352
- deployedAt: 1785173245463,
1353
- size: 77593,
1354
- hash: "0f1015e51702abd9834e295ea12ac8dbd906909d25f72ad6a509c061e625c75d",
1352
+ deployedAt: 1785226385509,
1353
+ size: 77655,
1354
+ hash: "3c2af3c3e62e8e606d35f81fd7e6f4943f8516a9bef74f4150c8c1767cbd316f",
1355
1355
  validatorWalletAddress: "0x82DB9F515957aA380B596C6eA2Bd30CEF181f236",
1356
1356
  pkp: {
1357
1357
  publicKey: "0x04cfccb9b6c7addc79469c0e9fafebef4c70801302c62cdb26b610723a9b8527d23f98a40158c7340d83fd0e62d02b5ec74c12f7a86d98e8c6973b4811110f19ad",
@@ -1359,17 +1359,17 @@ var require_pkg_src = __commonJS({
1359
1359
  }
1360
1360
  },
1361
1361
  extendPositionValidator: {
1362
- cid: "QmZyx9qUVyWu7deCJFLZxB1WDVRBgobs1Vm6m4ECGMbpkS",
1362
+ cid: "QmY2t41w1maaoDmdRPx6wTfciHPQAydSpLSKwKVFSS2DPM",
1363
1363
  authorizedCidHex: cidToHex(
1364
- "QmZyx9qUVyWu7deCJFLZxB1WDVRBgobs1Vm6m4ECGMbpkS"
1364
+ "QmY2t41w1maaoDmdRPx6wTfciHPQAydSpLSKwKVFSS2DPM"
1365
1365
  ),
1366
1366
  name: "Extend Position Validator",
1367
1367
  description: "Production Extend Position Validator",
1368
1368
  version: "1.2.1",
1369
1369
  deployed: true,
1370
- deployedAt: 1785173255906,
1371
- size: 75372,
1372
- hash: "545dc96a7e9b4d0aaadf239127b804a92df60b6b5b2fbb3203ef7de9ad97980a",
1370
+ deployedAt: 1785226398291,
1371
+ size: 75434,
1372
+ hash: "ba55532fbeaf6e65d180b869fd69ee06393d574daa0ace524a9e831d846539a5",
1373
1373
  validatorWalletAddress: "0x82DB9F515957aA380B596C6eA2Bd30CEF181f236",
1374
1374
  pkp: {
1375
1375
  publicKey: "0x04e52338f6a0c3362800f1a94c4c8f08be5030dde0fa217388c53d1c1a4790f4443c9f2886b2d2d8f4b75a9a156e9b028011b1a1cf7648da0e556aa980ec692836",
@@ -1377,17 +1377,17 @@ var require_pkg_src = __commonJS({
1377
1377
  }
1378
1378
  },
1379
1379
  btcWithdrawal: {
1380
- cid: "QmXKsozVz832mvU5xgvFnAAms1kfQrHAKj1areHfkDkoK7",
1380
+ cid: "QmcBg8vPXsCmiKDk28bJVTqDpTrwCzSYAGu5V6ABVVPuK5",
1381
1381
  authorizedCidHex: cidToHex(
1382
- "QmXKsozVz832mvU5xgvFnAAms1kfQrHAKj1areHfkDkoK7"
1382
+ "QmcBg8vPXsCmiKDk28bJVTqDpTrwCzSYAGu5V6ABVVPuK5"
1383
1383
  ),
1384
1384
  name: "Btc Withdrawal",
1385
1385
  description: "Production Btc Withdrawal",
1386
1386
  version: "1.2.1",
1387
1387
  deployed: true,
1388
- deployedAt: 1785173260209,
1389
- size: 92692,
1390
- hash: "18ade8e4f0c79896eee613d16c86de135f1d3daaa0fa056bcdbcaa0dff793c77",
1388
+ deployedAt: 1785226412397,
1389
+ size: 92754,
1390
+ hash: "d3a8ec62e0b1e6d0566a154a884bf7ee4e25ef6dc2dd84fde98211d25c1dede5",
1391
1391
  validatorWalletAddress: "0x82DB9F515957aA380B596C6eA2Bd30CEF181f236",
1392
1392
  pkp: {
1393
1393
  publicKey: "0x043616787c5432415c24378c4ef48de2bcd6bb7b575b837e3cff09171802662da7105d79586c7659677a0ecbaddac4cce06cb2a11f69a16fa0c4d7002ac7d51a4d",
@@ -1517,17 +1517,17 @@ var require_pkg_src = __commonJS({
1517
1517
  }
1518
1518
  },
1519
1519
  btcUtxoInvalidator: {
1520
- cid: "Qmc9W2dgGpRax5Q2nXw8ciGF9RHjWj1y9v2MMWNbrCwnZb",
1520
+ cid: "QmZE422cZsEjYN8pE6AmpkgFoZCK4UAfdDuzoVRRsMJbwm",
1521
1521
  authorizedCidHex: cidToHex(
1522
- "Qmc9W2dgGpRax5Q2nXw8ciGF9RHjWj1y9v2MMWNbrCwnZb"
1522
+ "QmZE422cZsEjYN8pE6AmpkgFoZCK4UAfdDuzoVRRsMJbwm"
1523
1523
  ),
1524
1524
  name: "Btc Utxo Invalidator",
1525
1525
  description: "Production Btc Utxo Invalidator",
1526
1526
  version: "1.0.0",
1527
1527
  deployed: true,
1528
- deployedAt: 1785173292828,
1529
- size: 61410,
1530
- hash: "9ca3817ea626b4ebca184e20cae827a8a982f48d6cd1497e81bb4469aa282627"
1528
+ deployedAt: 1785226423791,
1529
+ size: 61472,
1530
+ hash: "75eca528d8ac30ae8f21caaae206ccab162a83a048d622868e60f645f0c475e2"
1531
1531
  }
1532
1532
  };
1533
1533
  function getDeploymentsForNetwork(network) {
@@ -9178,6 +9178,23 @@ function createPKPManager(config) {
9178
9178
  // src/modules/loan/loan-creator.module.ts
9179
9179
  var import_ethers11 = require("ethers");
9180
9180
  var import_dh_lit_actions = __toESM(require_pkg_src());
9181
+
9182
+ // src/utils/contract-wallet.utils.ts
9183
+ var contractWalletCache = /* @__PURE__ */ new Map();
9184
+ async function isContractWallet(provider, address) {
9185
+ const { chainId } = await provider.getNetwork();
9186
+ const cacheKey = `${chainId}:${address.toLowerCase()}`;
9187
+ const cached = contractWalletCache.get(cacheKey);
9188
+ if (cached !== void 0)
9189
+ return cached;
9190
+ const code = await provider.getCode(address);
9191
+ const isContract = code !== "0x";
9192
+ contractWalletCache.set(cacheKey, isContract);
9193
+ return isContract;
9194
+ }
9195
+
9196
+ // src/modules/loan/loan-creator.module.ts
9197
+ var CONTRACT_WALLET_POLL_INTERVAL_MS = 4e3;
9181
9198
  var LoanCreator = class {
9182
9199
  config;
9183
9200
  transactionTimeoutMs;
@@ -9401,6 +9418,11 @@ var LoanCreator = class {
9401
9418
  validatorSignature: validatorSignature.substring(0, 20) + "..."
9402
9419
  });
9403
9420
  }
9421
+ this.config.onPkpCreated?.({
9422
+ tokenId: pkpData.tokenId,
9423
+ ethAddress: pkpData.ethAddress,
9424
+ publicKey: pkpData.publicKey
9425
+ });
9404
9426
  const addressesResult = await this.deriveBitcoinAddresses(
9405
9427
  pkpData.publicKey
9406
9428
  );
@@ -9573,6 +9595,12 @@ var LoanCreator = class {
9573
9595
  error: encErr instanceof Error ? encErr.message : String(encErr)
9574
9596
  });
9575
9597
  }
9598
+ const provider = this.config.contractManager.getProvider();
9599
+ const senderIsContractWallet = await isContractWallet(
9600
+ provider,
9601
+ await signerResult.value.getAddress()
9602
+ );
9603
+ const searchFromBlock = senderIsContractWallet ? await provider.getBlockNumber() : 0;
9576
9604
  const tx = await positionManager.createPosition(
9577
9605
  pkpIdBytes32,
9578
9606
  validatorSignature,
@@ -9594,19 +9622,20 @@ var LoanCreator = class {
9594
9622
  }
9595
9623
  if (this.config.debug) {
9596
9624
  log.info("\u23F3 Waiting for transaction confirmation", {
9597
- hash: tx.hash
9625
+ // For a contract wallet this is the wallet's own id, not an L1 hash — which is
9626
+ // exactly why the confirmation below does not wait on it.
9627
+ hash: tx.hash,
9628
+ senderIsContractWallet,
9629
+ searchFromBlock: senderIsContractWallet ? searchFromBlock : void 0
9598
9630
  });
9599
9631
  }
9600
9632
  const confirmations = await this.createPositionConfirmations();
9601
- const receipt = await Promise.race([
9602
- tx.wait(confirmations),
9603
- new Promise(
9604
- (_, reject) => setTimeout(
9605
- () => reject(new Error("Transaction confirmation timeout")),
9606
- this.transactionTimeoutMs
9607
- )
9608
- )
9609
- ]);
9633
+ const receipt = senderIsContractWallet ? await this.awaitPositionCreatedByPkpId(
9634
+ positionManager,
9635
+ pkpIdBytes32,
9636
+ searchFromBlock,
9637
+ confirmations
9638
+ ) : await this.awaitReceiptByHash(tx, confirmations);
9610
9639
  if (!receipt)
9611
9640
  throw new Error("Transaction was not mined (receipt is null)");
9612
9641
  if (this.config.debug && receipt.logs) {
@@ -9740,6 +9769,81 @@ var LoanCreator = class {
9740
9769
  }
9741
9770
  return 3;
9742
9771
  }
9772
+ /**
9773
+ * EOA path: the returned hash is the L1 hash, so `tx.wait` is exact.
9774
+ *
9775
+ * The timer is cleared on settle — an uncleared one keeps the process alive for the
9776
+ * full timeout after a fast confirmation, which in Node holds the event loop open.
9777
+ */
9778
+ async awaitReceiptByHash(tx, confirmations) {
9779
+ let timer;
9780
+ try {
9781
+ return await Promise.race([
9782
+ tx.wait(confirmations),
9783
+ new Promise((_, reject) => {
9784
+ timer = setTimeout(
9785
+ () => reject(new Error("Transaction confirmation timeout")),
9786
+ this.transactionTimeoutMs
9787
+ );
9788
+ })
9789
+ ]);
9790
+ } finally {
9791
+ if (timer)
9792
+ clearTimeout(timer);
9793
+ }
9794
+ }
9795
+ /**
9796
+ * Contract-wallet path: find this position by its `PositionCreated` log.
9797
+ *
9798
+ * `pkpId` is minted fresh per attempt and is the event's second indexed argument, so a
9799
+ * topic filter on it identifies exactly this position without reference to any transaction
9800
+ * hash. The filter deliberately leaves topic0 unconstrained: two `PositionCreated` ABIs are
9801
+ * in circulation (see `extractPositionId`) and matching on the freshly-minted pkpId alone,
9802
+ * scoped to this contract and to blocks at or after the send, is already unambiguous.
9803
+ *
9804
+ * The same confirmation depth as the EOA path is applied to the log's block, for the reason
9805
+ * given at the call site: `positionId` does not survive a reorg unchanged.
9806
+ */
9807
+ async awaitPositionCreatedByPkpId(positionManager, pkpIdBytes32, fromBlock, confirmations) {
9808
+ const provider = this.config.contractManager.getProvider();
9809
+ const contractAddress = await positionManager.getAddress();
9810
+ const deadline = Date.now() + this.transactionTimeoutMs;
9811
+ while (Date.now() < deadline) {
9812
+ const logs = await provider.getLogs({
9813
+ address: contractAddress,
9814
+ topics: [null, null, pkpIdBytes32],
9815
+ fromBlock,
9816
+ toBlock: "latest"
9817
+ });
9818
+ if (logs.length > 1) {
9819
+ throw new Error(
9820
+ `Expected at most one PositionCreated log for pkpId ${pkpIdBytes32}, found ${logs.length}`
9821
+ );
9822
+ }
9823
+ const positionLog = logs[0];
9824
+ if (positionLog) {
9825
+ const head = await provider.getBlockNumber();
9826
+ const depth = head - positionLog.blockNumber + 1;
9827
+ if (depth >= confirmations) {
9828
+ const receipt = await provider.getTransactionReceipt(
9829
+ positionLog.transactionHash
9830
+ );
9831
+ if (!receipt) {
9832
+ throw new Error(
9833
+ `PositionCreated log for pkpId ${pkpIdBytes32} has no receipt at ${positionLog.transactionHash} \u2014 the block was reorged out mid-confirmation.`
9834
+ );
9835
+ }
9836
+ return receipt;
9837
+ }
9838
+ }
9839
+ await new Promise(
9840
+ (resolve) => setTimeout(resolve, CONTRACT_WALLET_POLL_INTERVAL_MS)
9841
+ );
9842
+ }
9843
+ throw new Error(
9844
+ `Timed out after ${this.transactionTimeoutMs}ms waiting for the PositionCreated log for pkpId ${pkpIdBytes32}. The wallet may not have executed the transaction yet; the position must be rediscovered by pkpId before it is used.`
9845
+ );
9846
+ }
9743
9847
  /**
9744
9848
  * Re-read the receipt after confirmations and re-derive `positionId`, so a reorg
9745
9849
  * cannot leave the caller holding an id that never survived to the canonical chain.
@@ -18772,7 +18876,8 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
18772
18876
  litNetwork: config.litNetwork,
18773
18877
  loanCreationValidatorVersion: config.validators?.loanCreation ?? 1,
18774
18878
  ethRpcUrl: config.ethRpcUrl,
18775
- temperSignaturesTest: config.temperSignaturesTest
18879
+ temperSignaturesTest: config.temperSignaturesTest,
18880
+ onPkpCreated: config.onPkpCreated
18776
18881
  });
18777
18882
  if (!loanCreatorResult.success) {
18778
18883
  throw new Error(
package/dist/index.mjs CHANGED
@@ -1316,30 +1316,30 @@ var require_pkg_src = __commonJS({
1316
1316
  }
1317
1317
  },
1318
1318
  btcTransactionSigner: {
1319
- cid: "QmZFzjpdwpiBxHPv3t1mhjv8hfPRD1hPZGJ7jUU9w6V2Ca",
1319
+ cid: "QmPncBUbxN9giWntJcvBMFW9GDAgA3DwgAkUAHxSsY67ic",
1320
1320
  authorizedCidHex: cidToHex(
1321
- "QmZFzjpdwpiBxHPv3t1mhjv8hfPRD1hPZGJ7jUU9w6V2Ca"
1321
+ "QmPncBUbxN9giWntJcvBMFW9GDAgA3DwgAkUAHxSsY67ic"
1322
1322
  ),
1323
1323
  name: "Btc Transaction Signer",
1324
1324
  description: "Production Btc Transaction Signer",
1325
1325
  version: "1.1.1",
1326
1326
  deployed: true,
1327
- deployedAt: 1785173232972,
1328
- size: 66562,
1329
- hash: "13639ec13bfed381c3c9d81e17e37917446ba30d04d4d8e45809a6868139c3cb"
1327
+ deployedAt: 1785226367707,
1328
+ size: 66624,
1329
+ hash: "9e0d9909519d5133bab03a9491566870b08d8b42c80e2d768bd24f02946cc781"
1330
1330
  },
1331
1331
  ucdMintValidator: {
1332
- cid: "Qmb1TPCaNYRTHsnhZrE1J4BtVYNWBnWSneXRqyAco1XKku",
1332
+ cid: "QmPRLCfseSWCAS4PpvQWt9aEd6rXqWYG4JyGTn26KYk6xc",
1333
1333
  authorizedCidHex: cidToHex(
1334
- "Qmb1TPCaNYRTHsnhZrE1J4BtVYNWBnWSneXRqyAco1XKku"
1334
+ "QmPRLCfseSWCAS4PpvQWt9aEd6rXqWYG4JyGTn26KYk6xc"
1335
1335
  ),
1336
1336
  name: "Ucd Mint Validator",
1337
1337
  description: "Production Ucd Mint Validator",
1338
1338
  version: "1.2.1",
1339
1339
  deployed: true,
1340
- deployedAt: 1785173240530,
1341
- size: 81596,
1342
- hash: "fdaa7abb4ad28ae1f20f5cd6e3e03e5a8787fd6ac05938f51070ed16844f80f5",
1340
+ deployedAt: 1785226381631,
1341
+ size: 81658,
1342
+ hash: "d8ea21622885c3d26fdb64e2ba9d2f9460753a5cd7934b2928858899537443eb",
1343
1343
  validatorWalletAddress: "0x82DB9F515957aA380B596C6eA2Bd30CEF181f236",
1344
1344
  pkp: {
1345
1345
  publicKey: "0x041ab17cd91fc5c0b761eea6092d032807561b621b82c488826776e04a9158d61ba64d809a4729f0501289d980732cb06d8dfd06999dd9c8efd2f495dad78b31bb",
@@ -1347,17 +1347,17 @@ var require_pkg_src = __commonJS({
1347
1347
  }
1348
1348
  },
1349
1349
  processPaymentValidator: {
1350
- cid: "QmWSSAgmLtfVsRawHU2Uf72Xw4hM5T5Jcx2n7EVmEHQD1E",
1350
+ cid: "QmNUzmHQHsaKThGkfZiD3xZrN64qZfn4P6J4MqWgvkeEsX",
1351
1351
  authorizedCidHex: cidToHex(
1352
- "QmWSSAgmLtfVsRawHU2Uf72Xw4hM5T5Jcx2n7EVmEHQD1E"
1352
+ "QmNUzmHQHsaKThGkfZiD3xZrN64qZfn4P6J4MqWgvkeEsX"
1353
1353
  ),
1354
1354
  name: "Process Payment Validator",
1355
1355
  description: "Production Process Payment Validator",
1356
1356
  version: "1.2.1",
1357
1357
  deployed: true,
1358
- deployedAt: 1785173245463,
1359
- size: 77593,
1360
- hash: "0f1015e51702abd9834e295ea12ac8dbd906909d25f72ad6a509c061e625c75d",
1358
+ deployedAt: 1785226385509,
1359
+ size: 77655,
1360
+ hash: "3c2af3c3e62e8e606d35f81fd7e6f4943f8516a9bef74f4150c8c1767cbd316f",
1361
1361
  validatorWalletAddress: "0x82DB9F515957aA380B596C6eA2Bd30CEF181f236",
1362
1362
  pkp: {
1363
1363
  publicKey: "0x04cfccb9b6c7addc79469c0e9fafebef4c70801302c62cdb26b610723a9b8527d23f98a40158c7340d83fd0e62d02b5ec74c12f7a86d98e8c6973b4811110f19ad",
@@ -1365,17 +1365,17 @@ var require_pkg_src = __commonJS({
1365
1365
  }
1366
1366
  },
1367
1367
  extendPositionValidator: {
1368
- cid: "QmZyx9qUVyWu7deCJFLZxB1WDVRBgobs1Vm6m4ECGMbpkS",
1368
+ cid: "QmY2t41w1maaoDmdRPx6wTfciHPQAydSpLSKwKVFSS2DPM",
1369
1369
  authorizedCidHex: cidToHex(
1370
- "QmZyx9qUVyWu7deCJFLZxB1WDVRBgobs1Vm6m4ECGMbpkS"
1370
+ "QmY2t41w1maaoDmdRPx6wTfciHPQAydSpLSKwKVFSS2DPM"
1371
1371
  ),
1372
1372
  name: "Extend Position Validator",
1373
1373
  description: "Production Extend Position Validator",
1374
1374
  version: "1.2.1",
1375
1375
  deployed: true,
1376
- deployedAt: 1785173255906,
1377
- size: 75372,
1378
- hash: "545dc96a7e9b4d0aaadf239127b804a92df60b6b5b2fbb3203ef7de9ad97980a",
1376
+ deployedAt: 1785226398291,
1377
+ size: 75434,
1378
+ hash: "ba55532fbeaf6e65d180b869fd69ee06393d574daa0ace524a9e831d846539a5",
1379
1379
  validatorWalletAddress: "0x82DB9F515957aA380B596C6eA2Bd30CEF181f236",
1380
1380
  pkp: {
1381
1381
  publicKey: "0x04e52338f6a0c3362800f1a94c4c8f08be5030dde0fa217388c53d1c1a4790f4443c9f2886b2d2d8f4b75a9a156e9b028011b1a1cf7648da0e556aa980ec692836",
@@ -1383,17 +1383,17 @@ var require_pkg_src = __commonJS({
1383
1383
  }
1384
1384
  },
1385
1385
  btcWithdrawal: {
1386
- cid: "QmXKsozVz832mvU5xgvFnAAms1kfQrHAKj1areHfkDkoK7",
1386
+ cid: "QmcBg8vPXsCmiKDk28bJVTqDpTrwCzSYAGu5V6ABVVPuK5",
1387
1387
  authorizedCidHex: cidToHex(
1388
- "QmXKsozVz832mvU5xgvFnAAms1kfQrHAKj1areHfkDkoK7"
1388
+ "QmcBg8vPXsCmiKDk28bJVTqDpTrwCzSYAGu5V6ABVVPuK5"
1389
1389
  ),
1390
1390
  name: "Btc Withdrawal",
1391
1391
  description: "Production Btc Withdrawal",
1392
1392
  version: "1.2.1",
1393
1393
  deployed: true,
1394
- deployedAt: 1785173260209,
1395
- size: 92692,
1396
- hash: "18ade8e4f0c79896eee613d16c86de135f1d3daaa0fa056bcdbcaa0dff793c77",
1394
+ deployedAt: 1785226412397,
1395
+ size: 92754,
1396
+ hash: "d3a8ec62e0b1e6d0566a154a884bf7ee4e25ef6dc2dd84fde98211d25c1dede5",
1397
1397
  validatorWalletAddress: "0x82DB9F515957aA380B596C6eA2Bd30CEF181f236",
1398
1398
  pkp: {
1399
1399
  publicKey: "0x043616787c5432415c24378c4ef48de2bcd6bb7b575b837e3cff09171802662da7105d79586c7659677a0ecbaddac4cce06cb2a11f69a16fa0c4d7002ac7d51a4d",
@@ -1523,17 +1523,17 @@ var require_pkg_src = __commonJS({
1523
1523
  }
1524
1524
  },
1525
1525
  btcUtxoInvalidator: {
1526
- cid: "Qmc9W2dgGpRax5Q2nXw8ciGF9RHjWj1y9v2MMWNbrCwnZb",
1526
+ cid: "QmZE422cZsEjYN8pE6AmpkgFoZCK4UAfdDuzoVRRsMJbwm",
1527
1527
  authorizedCidHex: cidToHex(
1528
- "Qmc9W2dgGpRax5Q2nXw8ciGF9RHjWj1y9v2MMWNbrCwnZb"
1528
+ "QmZE422cZsEjYN8pE6AmpkgFoZCK4UAfdDuzoVRRsMJbwm"
1529
1529
  ),
1530
1530
  name: "Btc Utxo Invalidator",
1531
1531
  description: "Production Btc Utxo Invalidator",
1532
1532
  version: "1.0.0",
1533
1533
  deployed: true,
1534
- deployedAt: 1785173292828,
1535
- size: 61410,
1536
- hash: "9ca3817ea626b4ebca184e20cae827a8a982f48d6cd1497e81bb4469aa282627"
1534
+ deployedAt: 1785226423791,
1535
+ size: 61472,
1536
+ hash: "75eca528d8ac30ae8f21caaae206ccab162a83a048d622868e60f645f0c475e2"
1537
1537
  }
1538
1538
  };
1539
1539
  function getDeploymentsForNetwork(network) {
@@ -9099,6 +9099,23 @@ function createPKPManager(config) {
9099
9099
  // src/modules/loan/loan-creator.module.ts
9100
9100
  import { Contract as Contract3, Interface as Interface2, zeroPadValue as zeroPadValue4, toBeHex, SigningKey } from "ethers";
9101
9101
  var import_dh_lit_actions = __toESM(require_pkg_src());
9102
+
9103
+ // src/utils/contract-wallet.utils.ts
9104
+ var contractWalletCache = /* @__PURE__ */ new Map();
9105
+ async function isContractWallet(provider, address) {
9106
+ const { chainId } = await provider.getNetwork();
9107
+ const cacheKey = `${chainId}:${address.toLowerCase()}`;
9108
+ const cached = contractWalletCache.get(cacheKey);
9109
+ if (cached !== void 0)
9110
+ return cached;
9111
+ const code = await provider.getCode(address);
9112
+ const isContract = code !== "0x";
9113
+ contractWalletCache.set(cacheKey, isContract);
9114
+ return isContract;
9115
+ }
9116
+
9117
+ // src/modules/loan/loan-creator.module.ts
9118
+ var CONTRACT_WALLET_POLL_INTERVAL_MS = 4e3;
9102
9119
  var LoanCreator = class {
9103
9120
  config;
9104
9121
  transactionTimeoutMs;
@@ -9322,6 +9339,11 @@ var LoanCreator = class {
9322
9339
  validatorSignature: validatorSignature.substring(0, 20) + "..."
9323
9340
  });
9324
9341
  }
9342
+ this.config.onPkpCreated?.({
9343
+ tokenId: pkpData.tokenId,
9344
+ ethAddress: pkpData.ethAddress,
9345
+ publicKey: pkpData.publicKey
9346
+ });
9325
9347
  const addressesResult = await this.deriveBitcoinAddresses(
9326
9348
  pkpData.publicKey
9327
9349
  );
@@ -9494,6 +9516,12 @@ var LoanCreator = class {
9494
9516
  error: encErr instanceof Error ? encErr.message : String(encErr)
9495
9517
  });
9496
9518
  }
9519
+ const provider = this.config.contractManager.getProvider();
9520
+ const senderIsContractWallet = await isContractWallet(
9521
+ provider,
9522
+ await signerResult.value.getAddress()
9523
+ );
9524
+ const searchFromBlock = senderIsContractWallet ? await provider.getBlockNumber() : 0;
9497
9525
  const tx = await positionManager.createPosition(
9498
9526
  pkpIdBytes32,
9499
9527
  validatorSignature,
@@ -9515,19 +9543,20 @@ var LoanCreator = class {
9515
9543
  }
9516
9544
  if (this.config.debug) {
9517
9545
  log.info("\u23F3 Waiting for transaction confirmation", {
9518
- hash: tx.hash
9546
+ // For a contract wallet this is the wallet's own id, not an L1 hash — which is
9547
+ // exactly why the confirmation below does not wait on it.
9548
+ hash: tx.hash,
9549
+ senderIsContractWallet,
9550
+ searchFromBlock: senderIsContractWallet ? searchFromBlock : void 0
9519
9551
  });
9520
9552
  }
9521
9553
  const confirmations = await this.createPositionConfirmations();
9522
- const receipt = await Promise.race([
9523
- tx.wait(confirmations),
9524
- new Promise(
9525
- (_, reject) => setTimeout(
9526
- () => reject(new Error("Transaction confirmation timeout")),
9527
- this.transactionTimeoutMs
9528
- )
9529
- )
9530
- ]);
9554
+ const receipt = senderIsContractWallet ? await this.awaitPositionCreatedByPkpId(
9555
+ positionManager,
9556
+ pkpIdBytes32,
9557
+ searchFromBlock,
9558
+ confirmations
9559
+ ) : await this.awaitReceiptByHash(tx, confirmations);
9531
9560
  if (!receipt)
9532
9561
  throw new Error("Transaction was not mined (receipt is null)");
9533
9562
  if (this.config.debug && receipt.logs) {
@@ -9661,6 +9690,81 @@ var LoanCreator = class {
9661
9690
  }
9662
9691
  return 3;
9663
9692
  }
9693
+ /**
9694
+ * EOA path: the returned hash is the L1 hash, so `tx.wait` is exact.
9695
+ *
9696
+ * The timer is cleared on settle — an uncleared one keeps the process alive for the
9697
+ * full timeout after a fast confirmation, which in Node holds the event loop open.
9698
+ */
9699
+ async awaitReceiptByHash(tx, confirmations) {
9700
+ let timer;
9701
+ try {
9702
+ return await Promise.race([
9703
+ tx.wait(confirmations),
9704
+ new Promise((_, reject) => {
9705
+ timer = setTimeout(
9706
+ () => reject(new Error("Transaction confirmation timeout")),
9707
+ this.transactionTimeoutMs
9708
+ );
9709
+ })
9710
+ ]);
9711
+ } finally {
9712
+ if (timer)
9713
+ clearTimeout(timer);
9714
+ }
9715
+ }
9716
+ /**
9717
+ * Contract-wallet path: find this position by its `PositionCreated` log.
9718
+ *
9719
+ * `pkpId` is minted fresh per attempt and is the event's second indexed argument, so a
9720
+ * topic filter on it identifies exactly this position without reference to any transaction
9721
+ * hash. The filter deliberately leaves topic0 unconstrained: two `PositionCreated` ABIs are
9722
+ * in circulation (see `extractPositionId`) and matching on the freshly-minted pkpId alone,
9723
+ * scoped to this contract and to blocks at or after the send, is already unambiguous.
9724
+ *
9725
+ * The same confirmation depth as the EOA path is applied to the log's block, for the reason
9726
+ * given at the call site: `positionId` does not survive a reorg unchanged.
9727
+ */
9728
+ async awaitPositionCreatedByPkpId(positionManager, pkpIdBytes32, fromBlock, confirmations) {
9729
+ const provider = this.config.contractManager.getProvider();
9730
+ const contractAddress = await positionManager.getAddress();
9731
+ const deadline = Date.now() + this.transactionTimeoutMs;
9732
+ while (Date.now() < deadline) {
9733
+ const logs = await provider.getLogs({
9734
+ address: contractAddress,
9735
+ topics: [null, null, pkpIdBytes32],
9736
+ fromBlock,
9737
+ toBlock: "latest"
9738
+ });
9739
+ if (logs.length > 1) {
9740
+ throw new Error(
9741
+ `Expected at most one PositionCreated log for pkpId ${pkpIdBytes32}, found ${logs.length}`
9742
+ );
9743
+ }
9744
+ const positionLog = logs[0];
9745
+ if (positionLog) {
9746
+ const head = await provider.getBlockNumber();
9747
+ const depth = head - positionLog.blockNumber + 1;
9748
+ if (depth >= confirmations) {
9749
+ const receipt = await provider.getTransactionReceipt(
9750
+ positionLog.transactionHash
9751
+ );
9752
+ if (!receipt) {
9753
+ throw new Error(
9754
+ `PositionCreated log for pkpId ${pkpIdBytes32} has no receipt at ${positionLog.transactionHash} \u2014 the block was reorged out mid-confirmation.`
9755
+ );
9756
+ }
9757
+ return receipt;
9758
+ }
9759
+ }
9760
+ await new Promise(
9761
+ (resolve) => setTimeout(resolve, CONTRACT_WALLET_POLL_INTERVAL_MS)
9762
+ );
9763
+ }
9764
+ throw new Error(
9765
+ `Timed out after ${this.transactionTimeoutMs}ms waiting for the PositionCreated log for pkpId ${pkpIdBytes32}. The wallet may not have executed the transaction yet; the position must be rediscovered by pkpId before it is used.`
9766
+ );
9767
+ }
9664
9768
  /**
9665
9769
  * Re-read the receipt after confirmations and re-derive `positionId`, so a reorg
9666
9770
  * cannot leave the caller holding an id that never survived to the canonical chain.
@@ -18701,7 +18805,8 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
18701
18805
  litNetwork: config.litNetwork,
18702
18806
  loanCreationValidatorVersion: config.validators?.loanCreation ?? 1,
18703
18807
  ethRpcUrl: config.ethRpcUrl,
18704
- temperSignaturesTest: config.temperSignaturesTest
18808
+ temperSignaturesTest: config.temperSignaturesTest,
18809
+ onPkpCreated: config.onPkpCreated
18705
18810
  });
18706
18811
  if (!loanCreatorResult.success) {
18707
18812
  throw new Error(
@@ -102,6 +102,24 @@ interface BaseSDKConfig {
102
102
  * contract wallet can leave that request open for minutes.
103
103
  */
104
104
  onSessionSignatureResolved?: (ok: boolean) => void;
105
+ /**
106
+ * Fires during loan creation the moment the PKP has been minted and validated,
107
+ * before the `createPosition` transaction is submitted.
108
+ *
109
+ * The PKP is minted fresh per attempt, so `tokenId` is a unique, send-independent
110
+ * handle on the position that transaction is about to create — it is the only
111
+ * identifier a caller can hold *before* a hash exists. UIs use it to recognise
112
+ * their own position in an indexed feed without depending on the transaction
113
+ * hash, which a contract wallet does not return in a usable form.
114
+ *
115
+ * Note `tokenId` is a decimal string; the on-chain and subgraph `pkpId` is the
116
+ * same value as 32-byte hex. Normalise before comparing.
117
+ */
118
+ onPkpCreated?: (pkp: {
119
+ tokenId: string;
120
+ ethAddress: string;
121
+ publicKey: string;
122
+ }) => void;
105
123
  ethRpcUrl?: string;
106
124
  chainId?: number;
107
125
  networkOverride?: {
@@ -61,6 +61,15 @@ export interface LoanCreatorConfig {
61
61
  ethRpcUrl?: string;
62
62
  /** Security testing: Temper signatures to test contract validation */
63
63
  temperSignaturesTest?: boolean;
64
+ /**
65
+ * Fires once the PKP is minted and validated, before `createPosition` is submitted.
66
+ * See `SDKConfig.onPkpCreated` for why this exists and for the tokenId encoding caveat.
67
+ */
68
+ onPkpCreated?: (pkp: {
69
+ tokenId: string;
70
+ ethAddress: string;
71
+ publicKey: string;
72
+ }) => void;
64
73
  }
65
74
  /**
66
75
  * Loan creation audit trail
@@ -133,6 +142,26 @@ export declare class LoanCreator {
133
142
  * Override with `createPositionConfirmations` when a chain needs more.
134
143
  */
135
144
  private createPositionConfirmations;
145
+ /**
146
+ * EOA path: the returned hash is the L1 hash, so `tx.wait` is exact.
147
+ *
148
+ * The timer is cleared on settle — an uncleared one keeps the process alive for the
149
+ * full timeout after a fast confirmation, which in Node holds the event loop open.
150
+ */
151
+ private awaitReceiptByHash;
152
+ /**
153
+ * Contract-wallet path: find this position by its `PositionCreated` log.
154
+ *
155
+ * `pkpId` is minted fresh per attempt and is the event's second indexed argument, so a
156
+ * topic filter on it identifies exactly this position without reference to any transaction
157
+ * hash. The filter deliberately leaves topic0 unconstrained: two `PositionCreated` ABIs are
158
+ * in circulation (see `extractPositionId`) and matching on the freshly-minted pkpId alone,
159
+ * scoped to this contract and to blocks at or after the send, is already unambiguous.
160
+ *
161
+ * The same confirmation depth as the EOA path is applied to the log's block, for the reason
162
+ * given at the call site: `positionId` does not survive a reorg unchanged.
163
+ */
164
+ private awaitPositionCreatedByPkpId;
136
165
  /**
137
166
  * Re-read the receipt after confirmations and re-derive `positionId`, so a reorg
138
167
  * cannot leave the caller holding an id that never survived to the canonical chain.