@gvnrdao/dh-sdk 0.0.303 → 0.0.305
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/browser/dist/browser.js +1 -1
- package/dist/deployments.js +6 -2
- package/dist/deployments.mjs +6 -2
- package/dist/index.js +216 -58
- package/dist/index.mjs +216 -58
- package/dist/interfaces/chunks/loan-operations.i.d.ts +10 -0
- package/dist/modules/diamond-hands-sdk.d.ts +28 -4
- package/dist/utils/server-session.d.ts +31 -2
- package/package.json +3 -3
package/dist/deployments.js
CHANGED
|
@@ -413,9 +413,13 @@ var MAINNET_DEPLOYMENT = {
|
|
|
413
413
|
reason: "Validator gas fix (#420): BitcoinAddressValidator packed-table lookups; VERSION 1.0.0 -> 1.0.1"
|
|
414
414
|
},
|
|
415
415
|
UCDController: {
|
|
416
|
+
previousImplementation: "0x16f94AcC78cE87bEeBCfF90552091B3EfC071E48",
|
|
416
417
|
newImplementation: "0x28B8cAB89D89B3F83581FD2290de2Ce84535bd0A",
|
|
417
|
-
|
|
418
|
-
|
|
418
|
+
upgradedAt: "2026-07-06T10:41:59.000Z",
|
|
419
|
+
upgradedBy: "AdminModule/Safe audit-batch upgradeToAndCall; executed by 0xEba7BfAeB35ee18408b424Ee0BB45AdDf776589f in tx 0xf6609d3fa43b460d953c85d8d7265b59bf177723042db79a6a700571bad777b7 (block 25472962)",
|
|
420
|
+
reason: "Reconciled from chain \u2014 mainnet audit rollout batch (cross-ref onchain-auth/.safe-batches/mainnet-audit-execute.json)",
|
|
421
|
+
executeTx: "0xf6609d3fa43b460d953c85d8d7265b59bf177723042db79a6a700571bad777b7",
|
|
422
|
+
block: 25472962
|
|
419
423
|
},
|
|
420
424
|
PositionManagerCoreModule: {
|
|
421
425
|
previousImplementation: "0x6C8b0FB93F8d0239254aefaC24d4264cA2F8AAeB",
|
package/dist/deployments.mjs
CHANGED
|
@@ -380,9 +380,13 @@ var MAINNET_DEPLOYMENT = {
|
|
|
380
380
|
reason: "Validator gas fix (#420): BitcoinAddressValidator packed-table lookups; VERSION 1.0.0 -> 1.0.1"
|
|
381
381
|
},
|
|
382
382
|
UCDController: {
|
|
383
|
+
previousImplementation: "0x16f94AcC78cE87bEeBCfF90552091B3EfC071E48",
|
|
383
384
|
newImplementation: "0x28B8cAB89D89B3F83581FD2290de2Ce84535bd0A",
|
|
384
|
-
|
|
385
|
-
|
|
385
|
+
upgradedAt: "2026-07-06T10:41:59.000Z",
|
|
386
|
+
upgradedBy: "AdminModule/Safe audit-batch upgradeToAndCall; executed by 0xEba7BfAeB35ee18408b424Ee0BB45AdDf776589f in tx 0xf6609d3fa43b460d953c85d8d7265b59bf177723042db79a6a700571bad777b7 (block 25472962)",
|
|
387
|
+
reason: "Reconciled from chain \u2014 mainnet audit rollout batch (cross-ref onchain-auth/.safe-batches/mainnet-audit-execute.json)",
|
|
388
|
+
executeTx: "0xf6609d3fa43b460d953c85d8d7265b59bf177723042db79a6a700571bad777b7",
|
|
389
|
+
block: 25472962
|
|
386
390
|
},
|
|
387
391
|
PositionManagerCoreModule: {
|
|
388
392
|
previousImplementation: "0x6C8b0FB93F8d0239254aefaC24d4264cA2F8AAeB",
|
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
|
-
|
|
443
|
-
|
|
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",
|
|
@@ -1287,7 +1291,7 @@ var require_pkg_src = __commonJS({
|
|
|
1287
1291
|
description: "Production Pkp Validator",
|
|
1288
1292
|
version: "1.0.0",
|
|
1289
1293
|
deployed: true,
|
|
1290
|
-
deployedAt:
|
|
1294
|
+
deployedAt: 1784569687492,
|
|
1291
1295
|
size: 4140,
|
|
1292
1296
|
hash: "4c0d65bf1f33cdac22a78fd8c4764319cc3fe00650e0fe7fa8a6090d9a318a7b",
|
|
1293
1297
|
validatorWalletAddress: "0x82db9f515957aa380b596c6ea2bd30cef181f236",
|
|
@@ -1364,17 +1368,17 @@ var require_pkg_src = __commonJS({
|
|
|
1364
1368
|
}
|
|
1365
1369
|
},
|
|
1366
1370
|
btcWithdrawal: {
|
|
1367
|
-
cid: "
|
|
1371
|
+
cid: "QmexvpfHPacjsVcqNHHLyJhSnnAPLgbWmWd9N3NDLDvYds",
|
|
1368
1372
|
authorizedCidHex: cidToHex(
|
|
1369
|
-
"
|
|
1373
|
+
"QmexvpfHPacjsVcqNHHLyJhSnnAPLgbWmWd9N3NDLDvYds"
|
|
1370
1374
|
),
|
|
1371
1375
|
name: "Btc Withdrawal",
|
|
1372
1376
|
description: "Production Btc Withdrawal",
|
|
1373
|
-
version: "1.2.
|
|
1377
|
+
version: "1.2.3",
|
|
1374
1378
|
deployed: true,
|
|
1375
|
-
deployedAt:
|
|
1376
|
-
size:
|
|
1377
|
-
hash: "
|
|
1379
|
+
deployedAt: 1784585746901,
|
|
1380
|
+
size: 92027,
|
|
1381
|
+
hash: "7b4f4eab1f0c08b8b5b1c9cdb1064dd403ec13f57765919f62dec67fb8ba3c69",
|
|
1378
1382
|
validatorWalletAddress: "0x82DB9F515957aA380B596C6eA2Bd30CEF181f236",
|
|
1379
1383
|
pkp: {
|
|
1380
1384
|
publicKey: "0x043616787c5432415c24378c4ef48de2bcd6bb7b575b837e3cff09171802662da7105d79586c7659677a0ecbaddac4cce06cb2a11f69a16fa0c4d7002ac7d51a4d",
|
|
@@ -3746,12 +3750,23 @@ ${auth.clientId}`;
|
|
|
3746
3750
|
if (!data.vout || !Array.isArray(data.vout)) {
|
|
3747
3751
|
return null;
|
|
3748
3752
|
}
|
|
3749
|
-
return data.vout.map((output, index) =>
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3753
|
+
return data.vout.map((output, index) => {
|
|
3754
|
+
if (output.value === void 0) {
|
|
3755
|
+
throw new Error(
|
|
3756
|
+
`getTransactionOutputs(${txid}): output ${index} is missing its value \u2014 malformed provider response, refusing to return outputs that cannot be value-verified`
|
|
3757
|
+
);
|
|
3758
|
+
}
|
|
3759
|
+
assertSaneSatoshis(
|
|
3760
|
+
output.value,
|
|
3761
|
+
`getTransactionOutputs(${txid}) output ${index}`
|
|
3762
|
+
);
|
|
3763
|
+
return {
|
|
3764
|
+
index,
|
|
3765
|
+
scriptpubkey: output.scriptpubkey,
|
|
3766
|
+
scriptpubkey_address: output.scriptpubkey_address,
|
|
3767
|
+
value: output.value
|
|
3768
|
+
};
|
|
3769
|
+
});
|
|
3755
3770
|
} catch (error) {
|
|
3756
3771
|
clearTimeout(timeoutId);
|
|
3757
3772
|
if (isAbortError(error)) {
|
|
@@ -6602,6 +6617,14 @@ var ServerSession = class {
|
|
|
6602
6617
|
fetchImpl;
|
|
6603
6618
|
cached = null;
|
|
6604
6619
|
inFlight = null;
|
|
6620
|
+
/**
|
|
6621
|
+
* Bumped by `clearPersisted()` (logout / disconnect). An in-flight
|
|
6622
|
+
* `getOrRefresh()` captures this at start and refuses to write its freshly
|
|
6623
|
+
* minted token back to `this.cached`/the store if the value changed
|
|
6624
|
+
* meanwhile — so a refresh racing a sign-out can't silently "un-clear" the
|
|
6625
|
+
* credential it was told to drop.
|
|
6626
|
+
*/
|
|
6627
|
+
generation = 0;
|
|
6605
6628
|
/**
|
|
6606
6629
|
* Store key for the current signer, memoized on first use so the sync
|
|
6607
6630
|
* `clear()` can drop the persisted token without an async address lookup.
|
|
@@ -6617,8 +6640,22 @@ var ServerSession = class {
|
|
|
6617
6640
|
this.now = opts.now ?? (() => Math.floor(Date.now() / 1e3));
|
|
6618
6641
|
this.fetchImpl = opts.fetchImpl ?? ((...a) => fetch(...a));
|
|
6619
6642
|
}
|
|
6620
|
-
/**
|
|
6621
|
-
|
|
6643
|
+
/**
|
|
6644
|
+
* Returns a JWT good for at least `REFRESH_LEEWAY_SECONDS` more seconds.
|
|
6645
|
+
* Pass `{ silent: true }` to forbid a fresh wallet signature: it resolves ONLY
|
|
6646
|
+
* from a live cached token or the persisted re-mint envelope, never prompting
|
|
6647
|
+
* and never joining a prompt-capable in-flight refresh (used by `logout()`,
|
|
6648
|
+
* which must never pop the wallet during sign-out). Rejects when only a fresh
|
|
6649
|
+
* signature could produce a token.
|
|
6650
|
+
*/
|
|
6651
|
+
async getValidToken(opts) {
|
|
6652
|
+
if (opts?.silent) {
|
|
6653
|
+
const session2 = await this.tryResolveSilently(this.generation);
|
|
6654
|
+
if (!session2) {
|
|
6655
|
+
throw new Error("ServerSession: no existing session to refresh");
|
|
6656
|
+
}
|
|
6657
|
+
return session2.token;
|
|
6658
|
+
}
|
|
6622
6659
|
const session = await this.getOrRefresh();
|
|
6623
6660
|
return session.token;
|
|
6624
6661
|
}
|
|
@@ -6651,20 +6688,24 @@ var ServerSession = class {
|
|
|
6651
6688
|
* from storage).
|
|
6652
6689
|
*/
|
|
6653
6690
|
async clearPersisted() {
|
|
6691
|
+
this.generation += 1;
|
|
6654
6692
|
this.cached = null;
|
|
6655
6693
|
this.inFlight = null;
|
|
6656
6694
|
if (!this.store)
|
|
6657
6695
|
return;
|
|
6658
|
-
if (this.lastStoreKey) {
|
|
6659
|
-
this.store.clear(this.lastStoreKey);
|
|
6660
|
-
return;
|
|
6661
|
-
}
|
|
6662
6696
|
try {
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6697
|
+
if (this.lastStoreKey) {
|
|
6698
|
+
this.store.clear(this.lastStoreKey);
|
|
6699
|
+
} else {
|
|
6700
|
+
const address = (await this.signer.getAddress()).toLowerCase();
|
|
6701
|
+
this.store.clear(
|
|
6702
|
+
sessionStoreKey(address, this.chainId, this.serviceEndpoint)
|
|
6703
|
+
);
|
|
6704
|
+
}
|
|
6667
6705
|
} catch {
|
|
6706
|
+
} finally {
|
|
6707
|
+
this.generation += 1;
|
|
6708
|
+
this.cached = null;
|
|
6668
6709
|
}
|
|
6669
6710
|
}
|
|
6670
6711
|
/**
|
|
@@ -6674,7 +6715,8 @@ var ServerSession = class {
|
|
|
6674
6715
|
* of server response so the client stops presenting the token.
|
|
6675
6716
|
*/
|
|
6676
6717
|
async logout() {
|
|
6677
|
-
const
|
|
6718
|
+
const cached = this.cached;
|
|
6719
|
+
const token = cached && cached.expiresAt > this.now() ? cached.token : await this.getValidToken({ silent: true }).catch(() => null);
|
|
6678
6720
|
await this.clearPersisted();
|
|
6679
6721
|
if (!token)
|
|
6680
6722
|
return;
|
|
@@ -6689,6 +6731,50 @@ var ServerSession = class {
|
|
|
6689
6731
|
);
|
|
6690
6732
|
}
|
|
6691
6733
|
}
|
|
6734
|
+
/**
|
|
6735
|
+
* Resolve a session WITHOUT ever prompting for a wallet signature: a live
|
|
6736
|
+
* cached token, else the persisted JWT (adopted if still fresh, otherwise
|
|
6737
|
+
* silently re-minted from the envelope). Returns `null` only when a fresh
|
|
6738
|
+
* wallet signature would be required (dead/absent envelope). Never touches
|
|
6739
|
+
* `this.inFlight`, so a silent caller (logout) can resolve independently
|
|
6740
|
+
* instead of being dragged into a prompt-capable refresh already in flight.
|
|
6741
|
+
*
|
|
6742
|
+
* `gen` is the caller's clear-generation snapshot: writes to `this.cached`
|
|
6743
|
+
* and the store are skipped if a `clearPersisted()` landed meanwhile.
|
|
6744
|
+
*/
|
|
6745
|
+
async tryResolveSilently(gen) {
|
|
6746
|
+
const nowSec = this.now();
|
|
6747
|
+
if (this.cached && this.cached.expiresAt - REFRESH_LEEWAY_SECONDS > nowSec) {
|
|
6748
|
+
return this.cached;
|
|
6749
|
+
}
|
|
6750
|
+
const persisted = await this.loadPersisted();
|
|
6751
|
+
if (!persisted)
|
|
6752
|
+
return null;
|
|
6753
|
+
if (persisted.token && typeof persisted.tokenExpiresAt === "number" && persisted.tokenExpiresAt - REFRESH_LEEWAY_SECONDS > this.now()) {
|
|
6754
|
+
const adopted = {
|
|
6755
|
+
token: persisted.token,
|
|
6756
|
+
expiresAt: persisted.tokenExpiresAt
|
|
6757
|
+
};
|
|
6758
|
+
if (gen === this.generation)
|
|
6759
|
+
this.cached = adopted;
|
|
6760
|
+
return adopted;
|
|
6761
|
+
}
|
|
6762
|
+
try {
|
|
6763
|
+
const session = await this.login(persisted.payload);
|
|
6764
|
+
if (gen === this.generation) {
|
|
6765
|
+
this.persist(persisted.payload, session);
|
|
6766
|
+
this.cached = session;
|
|
6767
|
+
}
|
|
6768
|
+
return session;
|
|
6769
|
+
} catch (error) {
|
|
6770
|
+
if (!isLoginRejection(error))
|
|
6771
|
+
throw error;
|
|
6772
|
+
if (gen === this.generation && this.store && this.lastStoreKey) {
|
|
6773
|
+
this.store.clear(this.lastStoreKey);
|
|
6774
|
+
}
|
|
6775
|
+
return null;
|
|
6776
|
+
}
|
|
6777
|
+
}
|
|
6692
6778
|
async getOrRefresh() {
|
|
6693
6779
|
const nowSec = this.now();
|
|
6694
6780
|
if (this.cached && this.cached.expiresAt - REFRESH_LEEWAY_SECONDS > nowSec) {
|
|
@@ -6696,30 +6782,13 @@ var ServerSession = class {
|
|
|
6696
6782
|
}
|
|
6697
6783
|
if (this.inFlight)
|
|
6698
6784
|
return this.inFlight;
|
|
6785
|
+
const gen = this.generation;
|
|
6786
|
+
const notCleared = () => gen === this.generation;
|
|
6699
6787
|
this.inFlight = (async () => {
|
|
6700
6788
|
try {
|
|
6701
|
-
const
|
|
6702
|
-
if (
|
|
6703
|
-
|
|
6704
|
-
this.cached = {
|
|
6705
|
-
token: persisted.token,
|
|
6706
|
-
expiresAt: persisted.tokenExpiresAt
|
|
6707
|
-
};
|
|
6708
|
-
return this.cached;
|
|
6709
|
-
}
|
|
6710
|
-
try {
|
|
6711
|
-
const session2 = await this.login(persisted.payload);
|
|
6712
|
-
this.persist(persisted.payload, session2);
|
|
6713
|
-
this.cached = session2;
|
|
6714
|
-
return session2;
|
|
6715
|
-
} catch (error) {
|
|
6716
|
-
if (!isLoginRejection(error))
|
|
6717
|
-
throw error;
|
|
6718
|
-
if (this.store && this.lastStoreKey) {
|
|
6719
|
-
this.store.clear(this.lastStoreKey);
|
|
6720
|
-
}
|
|
6721
|
-
}
|
|
6722
|
-
}
|
|
6789
|
+
const existing = await this.tryResolveSilently(gen);
|
|
6790
|
+
if (existing)
|
|
6791
|
+
return existing;
|
|
6723
6792
|
this.onSignaturePrompt?.();
|
|
6724
6793
|
const payload = await buildSignedLoginPayload(
|
|
6725
6794
|
this.signer,
|
|
@@ -6727,11 +6796,14 @@ var ServerSession = class {
|
|
|
6727
6796
|
this.serviceEndpoint
|
|
6728
6797
|
);
|
|
6729
6798
|
const session = await this.login(payload);
|
|
6730
|
-
|
|
6731
|
-
|
|
6799
|
+
if (notCleared()) {
|
|
6800
|
+
this.persist(payload, session);
|
|
6801
|
+
this.cached = session;
|
|
6802
|
+
}
|
|
6732
6803
|
return session;
|
|
6733
6804
|
} finally {
|
|
6734
|
-
|
|
6805
|
+
if (notCleared())
|
|
6806
|
+
this.inFlight = null;
|
|
6735
6807
|
}
|
|
6736
6808
|
})();
|
|
6737
6809
|
return this.inFlight;
|
|
@@ -16104,13 +16176,25 @@ var DiamondHandsSDK = class _DiamondHandsSDK {
|
|
|
16104
16176
|
return this.serverSession.getAuthHeader();
|
|
16105
16177
|
}
|
|
16106
16178
|
/**
|
|
16107
|
-
*
|
|
16108
|
-
*
|
|
16109
|
-
*
|
|
16110
|
-
*
|
|
16179
|
+
* Sign out of the lit-ops-server session for the current auth signer. Call on
|
|
16180
|
+
* wallet disconnect or explicit sign-out so the credential does not outlive
|
|
16181
|
+
* the wallet connection. No-op in standalone mode.
|
|
16182
|
+
*
|
|
16183
|
+
* Attempts a server-side revocation first (`ServerSession.logout()` — which
|
|
16184
|
+
* tombstones the envelope's 24h re-mint window and invalidates the JWT), then
|
|
16185
|
+
* always removes the local credential. If the revocation call fails (offline,
|
|
16186
|
+
* server down, wallet already disconnected) we still clear locally so the
|
|
16187
|
+
* session cannot silently re-mint after sign-out; `logout()` is best-effort
|
|
16188
|
+
* and never prompts the wallet.
|
|
16111
16189
|
*/
|
|
16112
16190
|
async clearServerSession() {
|
|
16113
|
-
|
|
16191
|
+
if (!this.serverSession)
|
|
16192
|
+
return;
|
|
16193
|
+
try {
|
|
16194
|
+
await this.serverSession.logout();
|
|
16195
|
+
} catch {
|
|
16196
|
+
await this.serverSession.clearPersisted();
|
|
16197
|
+
}
|
|
16114
16198
|
}
|
|
16115
16199
|
/**
|
|
16116
16200
|
* Audit H-9: invalidate the LoanQuery cache so subsequent reads return
|
|
@@ -20685,7 +20769,9 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
|
|
|
20685
20769
|
gasUsed: receipt.gasUsed?.toString() || "unknown",
|
|
20686
20770
|
utxoTxid: validationResponse.utxoTxid,
|
|
20687
20771
|
utxoVout: validationResponse.utxoVout,
|
|
20688
|
-
utxoSatoshis: validationResponse.utxoSatoshis
|
|
20772
|
+
utxoSatoshis: validationResponse.utxoSatoshis,
|
|
20773
|
+
// Phase B: full consensus-validated spend set (absent on older actions).
|
|
20774
|
+
confirmedUtxos: validationResponse.confirmedUtxos
|
|
20689
20775
|
};
|
|
20690
20776
|
} catch (error) {
|
|
20691
20777
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
@@ -20715,6 +20801,42 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
|
|
|
20715
20801
|
};
|
|
20716
20802
|
}
|
|
20717
20803
|
}
|
|
20804
|
+
/**
|
|
20805
|
+
* TEMPORARY (multi-UTXO withdrawal fix, Phase A): fetch the vault's confirmed
|
|
20806
|
+
* UTXO set from lit-ops-server (`GET /api/lit/vault-utxos`) so the caller can
|
|
20807
|
+
* assemble and sign the FULL input set for a multi-UTXO consolidation
|
|
20808
|
+
* withdrawal. Phase 1 only returns ONE representative UTXO, so a vault whose
|
|
20809
|
+
* balance is spread across several UTXOs otherwise fails the Phase-2 signer
|
|
20810
|
+
* with "Insufficient UTXO value ... across 1 input(s)".
|
|
20811
|
+
*
|
|
20812
|
+
* Returns `[]` on any failure (non-service mode, network error, bad shape) so
|
|
20813
|
+
* callers transparently fall back to the single authorized UTXO. Superseded
|
|
20814
|
+
* by the btc-withdrawal Lit Action returning its own confirmedUTXOs (Phase B).
|
|
20815
|
+
*/
|
|
20816
|
+
async fetchConfirmedVaultUtxos(positionId) {
|
|
20817
|
+
if (this.config.mode !== "service" || !this.config.serviceEndpoint)
|
|
20818
|
+
return [];
|
|
20819
|
+
try {
|
|
20820
|
+
const pid = positionId.startsWith("0x") ? positionId : `0x${positionId}`;
|
|
20821
|
+
const resp = await fetch(
|
|
20822
|
+
`${this.config.serviceEndpoint}/api/lit/vault-utxos?positionId=${encodeURIComponent(pid)}`,
|
|
20823
|
+
{ method: "GET", headers: { ...await this.getAuthHeader() } }
|
|
20824
|
+
);
|
|
20825
|
+
if (!resp.ok)
|
|
20826
|
+
return [];
|
|
20827
|
+
const json = await resp.json();
|
|
20828
|
+
if (!json.success || !Array.isArray(json.data?.utxos))
|
|
20829
|
+
return [];
|
|
20830
|
+
return json.data.utxos.map((u) => ({
|
|
20831
|
+
txid: String(u.txid),
|
|
20832
|
+
vout: Number(u.vout),
|
|
20833
|
+
value: Number(u.value),
|
|
20834
|
+
confirmations: Number(u.confirmations ?? 0)
|
|
20835
|
+
}));
|
|
20836
|
+
} catch {
|
|
20837
|
+
return [];
|
|
20838
|
+
}
|
|
20839
|
+
}
|
|
20718
20840
|
/**
|
|
20719
20841
|
* Execute Bitcoin withdrawal (Phase 2)
|
|
20720
20842
|
*
|
|
@@ -21331,13 +21453,49 @@ Message: ${causeMessage}${quantumContext}${mintDebtDiagnostics}`
|
|
|
21331
21453
|
if (this.config.debug) {
|
|
21332
21454
|
log.info("\u{1F50D} Found vault UTXO for execution", { utxoIdentifier });
|
|
21333
21455
|
}
|
|
21456
|
+
let executionUtxos;
|
|
21457
|
+
const gatheredUtxos = authResult.confirmedUtxos && authResult.confirmedUtxos.length > 0 ? authResult.confirmedUtxos.map((u) => ({
|
|
21458
|
+
txid: u.txid,
|
|
21459
|
+
vout: Number(u.vout),
|
|
21460
|
+
value: Number(u.value),
|
|
21461
|
+
confirmations: 0
|
|
21462
|
+
})) : await this.fetchConfirmedVaultUtxos(positionId);
|
|
21463
|
+
if (gatheredUtxos.length > 0) {
|
|
21464
|
+
const normTxid = (t) => String(t).toLowerCase().replace(/^0x/, "");
|
|
21465
|
+
const byOutpoint = /* @__PURE__ */ new Map();
|
|
21466
|
+
for (const u of gatheredUtxos) {
|
|
21467
|
+
const txid = normTxid(u.txid);
|
|
21468
|
+
byOutpoint.set(`${txid}:${u.vout}`, {
|
|
21469
|
+
txid,
|
|
21470
|
+
vout: Number(u.vout),
|
|
21471
|
+
value: Number(u.value)
|
|
21472
|
+
});
|
|
21473
|
+
}
|
|
21474
|
+
const repKey = `${normTxid(authResult.utxoTxid)}:${authResult.utxoVout}`;
|
|
21475
|
+
if (!byOutpoint.has(repKey)) {
|
|
21476
|
+
byOutpoint.set(repKey, {
|
|
21477
|
+
txid: normTxid(authResult.utxoTxid),
|
|
21478
|
+
vout: Number(authResult.utxoVout),
|
|
21479
|
+
value: Number(authResult.utxoSatoshis)
|
|
21480
|
+
});
|
|
21481
|
+
}
|
|
21482
|
+
if (byOutpoint.size > 1) {
|
|
21483
|
+
executionUtxos = Array.from(byOutpoint.values());
|
|
21484
|
+
if (this.config.debug) {
|
|
21485
|
+
log.info("\u{1F9E9} Multi-UTXO withdrawal: signing full input set", {
|
|
21486
|
+
inputs: executionUtxos.length
|
|
21487
|
+
});
|
|
21488
|
+
}
|
|
21489
|
+
}
|
|
21490
|
+
}
|
|
21334
21491
|
const executionResult = await this.executeBTCWithdrawal({
|
|
21335
21492
|
positionId,
|
|
21336
21493
|
utxoIdentifier,
|
|
21337
21494
|
utxoSatoshis: Number(authResult.utxoSatoshis),
|
|
21338
21495
|
networkFee,
|
|
21339
21496
|
destination: withdrawalAddress,
|
|
21340
|
-
targetAmount: withdrawalAmount
|
|
21497
|
+
targetAmount: withdrawalAmount,
|
|
21498
|
+
...executionUtxos ? { utxos: executionUtxos } : {}
|
|
21341
21499
|
});
|
|
21342
21500
|
if (this.config.debug) {
|
|
21343
21501
|
log.info("\u2705 Phase 2 complete: Bitcoin transaction executed", {
|