@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: "
|
|
1313
|
+
cid: "QmPncBUbxN9giWntJcvBMFW9GDAgA3DwgAkUAHxSsY67ic",
|
|
1314
1314
|
authorizedCidHex: cidToHex(
|
|
1315
|
-
"
|
|
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:
|
|
1322
|
-
size:
|
|
1323
|
-
hash: "
|
|
1321
|
+
deployedAt: 1785226367707,
|
|
1322
|
+
size: 66624,
|
|
1323
|
+
hash: "9e0d9909519d5133bab03a9491566870b08d8b42c80e2d768bd24f02946cc781"
|
|
1324
1324
|
},
|
|
1325
1325
|
ucdMintValidator: {
|
|
1326
|
-
cid: "
|
|
1326
|
+
cid: "QmPRLCfseSWCAS4PpvQWt9aEd6rXqWYG4JyGTn26KYk6xc",
|
|
1327
1327
|
authorizedCidHex: cidToHex(
|
|
1328
|
-
"
|
|
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:
|
|
1335
|
-
size:
|
|
1336
|
-
hash: "
|
|
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: "
|
|
1344
|
+
cid: "QmNUzmHQHsaKThGkfZiD3xZrN64qZfn4P6J4MqWgvkeEsX",
|
|
1345
1345
|
authorizedCidHex: cidToHex(
|
|
1346
|
-
"
|
|
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:
|
|
1353
|
-
size:
|
|
1354
|
-
hash: "
|
|
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: "
|
|
1362
|
+
cid: "QmY2t41w1maaoDmdRPx6wTfciHPQAydSpLSKwKVFSS2DPM",
|
|
1363
1363
|
authorizedCidHex: cidToHex(
|
|
1364
|
-
"
|
|
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:
|
|
1371
|
-
size:
|
|
1372
|
-
hash: "
|
|
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: "
|
|
1380
|
+
cid: "QmcBg8vPXsCmiKDk28bJVTqDpTrwCzSYAGu5V6ABVVPuK5",
|
|
1381
1381
|
authorizedCidHex: cidToHex(
|
|
1382
|
-
"
|
|
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:
|
|
1389
|
-
size:
|
|
1390
|
-
hash: "
|
|
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: "
|
|
1520
|
+
cid: "QmZE422cZsEjYN8pE6AmpkgFoZCK4UAfdDuzoVRRsMJbwm",
|
|
1521
1521
|
authorizedCidHex: cidToHex(
|
|
1522
|
-
"
|
|
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:
|
|
1529
|
-
size:
|
|
1530
|
-
hash: "
|
|
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
|
|
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
|
|
9602
|
-
|
|
9603
|
-
|
|
9604
|
-
|
|
9605
|
-
|
|
9606
|
-
|
|
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: "
|
|
1319
|
+
cid: "QmPncBUbxN9giWntJcvBMFW9GDAgA3DwgAkUAHxSsY67ic",
|
|
1320
1320
|
authorizedCidHex: cidToHex(
|
|
1321
|
-
"
|
|
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:
|
|
1328
|
-
size:
|
|
1329
|
-
hash: "
|
|
1327
|
+
deployedAt: 1785226367707,
|
|
1328
|
+
size: 66624,
|
|
1329
|
+
hash: "9e0d9909519d5133bab03a9491566870b08d8b42c80e2d768bd24f02946cc781"
|
|
1330
1330
|
},
|
|
1331
1331
|
ucdMintValidator: {
|
|
1332
|
-
cid: "
|
|
1332
|
+
cid: "QmPRLCfseSWCAS4PpvQWt9aEd6rXqWYG4JyGTn26KYk6xc",
|
|
1333
1333
|
authorizedCidHex: cidToHex(
|
|
1334
|
-
"
|
|
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:
|
|
1341
|
-
size:
|
|
1342
|
-
hash: "
|
|
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: "
|
|
1350
|
+
cid: "QmNUzmHQHsaKThGkfZiD3xZrN64qZfn4P6J4MqWgvkeEsX",
|
|
1351
1351
|
authorizedCidHex: cidToHex(
|
|
1352
|
-
"
|
|
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:
|
|
1359
|
-
size:
|
|
1360
|
-
hash: "
|
|
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: "
|
|
1368
|
+
cid: "QmY2t41w1maaoDmdRPx6wTfciHPQAydSpLSKwKVFSS2DPM",
|
|
1369
1369
|
authorizedCidHex: cidToHex(
|
|
1370
|
-
"
|
|
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:
|
|
1377
|
-
size:
|
|
1378
|
-
hash: "
|
|
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: "
|
|
1386
|
+
cid: "QmcBg8vPXsCmiKDk28bJVTqDpTrwCzSYAGu5V6ABVVPuK5",
|
|
1387
1387
|
authorizedCidHex: cidToHex(
|
|
1388
|
-
"
|
|
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:
|
|
1395
|
-
size:
|
|
1396
|
-
hash: "
|
|
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: "
|
|
1526
|
+
cid: "QmZE422cZsEjYN8pE6AmpkgFoZCK4UAfdDuzoVRRsMJbwm",
|
|
1527
1527
|
authorizedCidHex: cidToHex(
|
|
1528
|
-
"
|
|
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:
|
|
1535
|
-
size:
|
|
1536
|
-
hash: "
|
|
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
|
|
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
|
|
9523
|
-
|
|
9524
|
-
|
|
9525
|
-
|
|
9526
|
-
|
|
9527
|
-
|
|
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.
|