@gvnrdao/dh-sdk 0.0.270 → 0.0.271
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/index.js +89 -308
- package/dist/index.mjs +89 -308
- package/dist/modules/bitcoin/bitcoin-operations.module.d.ts +8 -6
- package/dist/server.js +1 -1
- package/dist/server.mjs +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -31155,7 +31155,6 @@ var require_pkg_src = __commonJS({
|
|
|
31155
31155
|
executeLitAction: () => executeLitAction,
|
|
31156
31156
|
executePkpOperation: () => executePkpOperation,
|
|
31157
31157
|
executePriceOracle: () => executePriceOracle,
|
|
31158
|
-
executePriceOracleConsensus: () => executePriceOracleConsensus,
|
|
31159
31158
|
executeVaultSnapshot: () => executeVaultSnapshot,
|
|
31160
31159
|
generateSessionSignatures: () => generateSessionSignatures,
|
|
31161
31160
|
generateSessionSignaturesWithCache: () => generateSessionSignaturesWithCache,
|
|
@@ -31398,17 +31397,17 @@ var require_pkg_src = __commonJS({
|
|
|
31398
31397
|
hash: "856da2d48ac2b76fc0d493a5a3df2decbf8e0fbbaff550996a0c48733bdd4660"
|
|
31399
31398
|
},
|
|
31400
31399
|
ucdMintValidator: {
|
|
31401
|
-
cid: "
|
|
31400
|
+
cid: "QmWZJpS3Q25XKo9ptzVcYz7pnW5hbqhuSvrhu7Qo7EcxEk",
|
|
31402
31401
|
authorizedCidHex: cidToHex(
|
|
31403
|
-
"
|
|
31402
|
+
"QmWZJpS3Q25XKo9ptzVcYz7pnW5hbqhuSvrhu7Qo7EcxEk"
|
|
31404
31403
|
),
|
|
31405
31404
|
name: "Ucd Mint Validator",
|
|
31406
31405
|
description: "Production Ucd Mint Validator",
|
|
31407
31406
|
version: "1.0.0",
|
|
31408
31407
|
deployed: true,
|
|
31409
|
-
deployedAt:
|
|
31410
|
-
size:
|
|
31411
|
-
hash: "
|
|
31408
|
+
deployedAt: 1780330809889,
|
|
31409
|
+
size: 66616,
|
|
31410
|
+
hash: "6015049e636fc2dd4dcce07e2f2bc1df20a8e8c466a5f054918e5f6773c26ac4",
|
|
31412
31411
|
validatorWalletAddress: "0x36f3dd61c4c08a56d29ed2fd6d5f111b67b6a7a1",
|
|
31413
31412
|
pkp: {
|
|
31414
31413
|
publicKey: "0x041ab17cd91fc5c0b761eea6092d032807561b621b82c488826776e04a9158d61ba64d809a4729f0501289d980732cb06d8dfd06999dd9c8efd2f495dad78b31bb",
|
|
@@ -31416,17 +31415,17 @@ var require_pkg_src = __commonJS({
|
|
|
31416
31415
|
}
|
|
31417
31416
|
},
|
|
31418
31417
|
processPaymentValidator: {
|
|
31419
|
-
cid: "
|
|
31418
|
+
cid: "QmRZjMcJzEAzepwN3uJBbgGxMPULvCw6LMpQ94w19sv3Cx",
|
|
31420
31419
|
authorizedCidHex: cidToHex(
|
|
31421
|
-
"
|
|
31420
|
+
"QmRZjMcJzEAzepwN3uJBbgGxMPULvCw6LMpQ94w19sv3Cx"
|
|
31422
31421
|
),
|
|
31423
31422
|
name: "Process Payment Validator",
|
|
31424
31423
|
description: "Production Process Payment Validator",
|
|
31425
31424
|
version: "1.0.0",
|
|
31426
31425
|
deployed: true,
|
|
31427
|
-
deployedAt:
|
|
31428
|
-
size:
|
|
31429
|
-
hash: "
|
|
31426
|
+
deployedAt: 1780330829127,
|
|
31427
|
+
size: 62605,
|
|
31428
|
+
hash: "44e7fa2bc52d08c52821945a2bfd8fb8a5745d1f5669b2a45666fa34e7966198",
|
|
31430
31429
|
validatorWalletAddress: "0xc2ed5a59bd81eb4d1a19a0147b86ab69aa4c28ba",
|
|
31431
31430
|
pkp: {
|
|
31432
31431
|
publicKey: "0x04cfccb9b6c7addc79469c0e9fafebef4c70801302c62cdb26b610723a9b8527d23f98a40158c7340d83fd0e62d02b5ec74c12f7a86d98e8c6973b4811110f19ad",
|
|
@@ -31434,17 +31433,17 @@ var require_pkg_src = __commonJS({
|
|
|
31434
31433
|
}
|
|
31435
31434
|
},
|
|
31436
31435
|
extendPositionValidator: {
|
|
31437
|
-
cid: "
|
|
31436
|
+
cid: "Qmb4y62Ftjar5EXcREyXC84U7QEMhCQgycHYCmJxLichvt",
|
|
31438
31437
|
authorizedCidHex: cidToHex(
|
|
31439
|
-
"
|
|
31438
|
+
"Qmb4y62Ftjar5EXcREyXC84U7QEMhCQgycHYCmJxLichvt"
|
|
31440
31439
|
),
|
|
31441
31440
|
name: "Extend Position Validator",
|
|
31442
31441
|
description: "Production Extend Position Validator",
|
|
31443
31442
|
version: "1.0.1",
|
|
31444
31443
|
deployed: true,
|
|
31445
|
-
deployedAt:
|
|
31446
|
-
size:
|
|
31447
|
-
hash: "
|
|
31444
|
+
deployedAt: 1780330862404,
|
|
31445
|
+
size: 62034,
|
|
31446
|
+
hash: "2eedfed0a406fa24457b29621de7657ca598bf9a3bc928ea5d5febdeef17c1e1",
|
|
31448
31447
|
validatorWalletAddress: "0xb3f4271c475887a86a2f21446f0968c30cc74c97",
|
|
31449
31448
|
pkp: {
|
|
31450
31449
|
publicKey: "0x04e52338f6a0c3362800f1a94c4c8f08be5030dde0fa217388c53d1c1a4790f4443c9f2886b2d2d8f4b75a9a156e9b028011b1a1cf7648da0e556aa980ec692836",
|
|
@@ -31452,17 +31451,17 @@ var require_pkg_src = __commonJS({
|
|
|
31452
31451
|
}
|
|
31453
31452
|
},
|
|
31454
31453
|
btcWithdrawal: {
|
|
31455
|
-
cid: "
|
|
31454
|
+
cid: "QmetrNkAUQ54PHzHLRR7TfDk3oGKnCf22m2bQwj24eB253",
|
|
31456
31455
|
authorizedCidHex: cidToHex(
|
|
31457
|
-
"
|
|
31456
|
+
"QmetrNkAUQ54PHzHLRR7TfDk3oGKnCf22m2bQwj24eB253"
|
|
31458
31457
|
),
|
|
31459
31458
|
name: "Btc Withdrawal",
|
|
31460
31459
|
description: "Production Btc Withdrawal",
|
|
31461
31460
|
version: "1.0.0",
|
|
31462
31461
|
deployed: true,
|
|
31463
|
-
deployedAt:
|
|
31464
|
-
size:
|
|
31465
|
-
hash: "
|
|
31462
|
+
deployedAt: 1780330882060,
|
|
31463
|
+
size: 73295,
|
|
31464
|
+
hash: "c31e8f993806e8031fec42712eca04cb2e3b12f4ff37db98bcd28f46c766d710",
|
|
31466
31465
|
validatorWalletAddress: "0xbb137fbda353199e9419b698c57a742124d4987d",
|
|
31467
31466
|
pkp: {
|
|
31468
31467
|
publicKey: "0x043616787c5432415c24378c4ef48de2bcd6bb7b575b837e3cff09171802662da7105d79586c7659677a0ecbaddac4cce06cb2a11f69a16fa0c4d7002ac7d51a4d",
|
|
@@ -31470,17 +31469,17 @@ var require_pkg_src = __commonJS({
|
|
|
31470
31469
|
}
|
|
31471
31470
|
},
|
|
31472
31471
|
liquidationValidator: {
|
|
31473
|
-
cid: "
|
|
31472
|
+
cid: "QmRuLKJmsD8yN6Ez89L9mzSM3zyarjGwFMBwn23CkajizZ",
|
|
31474
31473
|
authorizedCidHex: cidToHex(
|
|
31475
|
-
"
|
|
31474
|
+
"QmRuLKJmsD8yN6Ez89L9mzSM3zyarjGwFMBwn23CkajizZ"
|
|
31476
31475
|
),
|
|
31477
31476
|
name: "Liquidation Validator",
|
|
31478
31477
|
description: "Production Liquidation Validator",
|
|
31479
31478
|
version: "1.0.0",
|
|
31480
31479
|
deployed: true,
|
|
31481
|
-
deployedAt:
|
|
31482
|
-
size:
|
|
31483
|
-
hash: "
|
|
31480
|
+
deployedAt: 1780330901287,
|
|
31481
|
+
size: 53200,
|
|
31482
|
+
hash: "7bb6d4451dbdcc4f5e4d60bf15db064608877afb4800e44f186fcb987194c36b",
|
|
31484
31483
|
validatorWalletAddress: "0x1542f863ee0340f6a067573e80ae66dd9b3838fa",
|
|
31485
31484
|
pkp: {
|
|
31486
31485
|
publicKey: "0x041a241de58976c13e3d7ca5a18e494f7330151e3818706135d50176e78ffb673e58b11f0b67a87c73fade6c6b27d6e7a7377ea9f4c10bf31880f1d725f18cc6f8",
|
|
@@ -31488,17 +31487,17 @@ var require_pkg_src = __commonJS({
|
|
|
31488
31487
|
}
|
|
31489
31488
|
},
|
|
31490
31489
|
priceOracle: {
|
|
31491
|
-
cid: "
|
|
31490
|
+
cid: "QmR5mjqhxfEPuBMbxhcXkJpdAMDzYfkpUWPgcPNCiSuhqh",
|
|
31492
31491
|
authorizedCidHex: cidToHex(
|
|
31493
|
-
"
|
|
31492
|
+
"QmR5mjqhxfEPuBMbxhcXkJpdAMDzYfkpUWPgcPNCiSuhqh"
|
|
31494
31493
|
),
|
|
31495
31494
|
name: "Price Oracle",
|
|
31496
31495
|
description: "Production Price Oracle (Chipotle main+getPrivateKey)",
|
|
31497
31496
|
version: "1.1.0",
|
|
31498
31497
|
deployed: true,
|
|
31499
|
-
deployedAt:
|
|
31500
|
-
size:
|
|
31501
|
-
hash: "
|
|
31498
|
+
deployedAt: 1780330918696,
|
|
31499
|
+
size: 8134,
|
|
31500
|
+
hash: "7aa3339f0501c3f628e4eaf00d39cfff76789d923aa440894c4e5a0b696c7f12",
|
|
31502
31501
|
validatorWalletAddress: "0x831ddf3048547b983efe3ccbbb35a45a53191651",
|
|
31503
31502
|
pkp: {
|
|
31504
31503
|
publicKey: "0x043beaa1da47875601a8d6f430b1438ee2d4732eefd06e5c63a474bbdaf9e7df1797b1b951e041b627c2bf839788164825324c9cbd1e2d6f740fdd4bff69b1900b",
|
|
@@ -31506,17 +31505,17 @@ var require_pkg_src = __commonJS({
|
|
|
31506
31505
|
}
|
|
31507
31506
|
},
|
|
31508
31507
|
loanVaultBtcBalance: {
|
|
31509
|
-
cid: "
|
|
31508
|
+
cid: "QmbXoFbhtqWsgKkLxtxwd6fDuKvvBpPhpMmdqUU1UC9GMn",
|
|
31510
31509
|
authorizedCidHex: cidToHex(
|
|
31511
|
-
"
|
|
31510
|
+
"QmbXoFbhtqWsgKkLxtxwd6fDuKvvBpPhpMmdqUU1UC9GMn"
|
|
31512
31511
|
),
|
|
31513
31512
|
name: "Loan Vault Btc Balance",
|
|
31514
31513
|
description: "Production Loan Vault Btc Balance",
|
|
31515
31514
|
version: "1.0.0",
|
|
31516
31515
|
deployed: true,
|
|
31517
|
-
deployedAt:
|
|
31518
|
-
size:
|
|
31519
|
-
hash: "
|
|
31516
|
+
deployedAt: 1780330936276,
|
|
31517
|
+
size: 43046,
|
|
31518
|
+
hash: "160e4ed6d0c05871d65408906cb2ce900f3ce67a2a3a27549254773e3569d37e",
|
|
31520
31519
|
validatorWalletAddress: "0x47feea74c8739d24b44faa67217f2f99970e15e7",
|
|
31521
31520
|
pkp: {
|
|
31522
31521
|
publicKey: "0x043616787c5432415c24378c4ef48de2bcd6bb7b575b837e3cff09171802662da7105d79586c7659677a0ecbaddac4cce06cb2a11f69a16fa0c4d7002ac7d51a4d",
|
|
@@ -32312,14 +32311,11 @@ ${errorReport}`);
|
|
|
32312
32311
|
init_debug_logger();
|
|
32313
32312
|
init_session_signature_cache();
|
|
32314
32313
|
var import_ethers13 = require_lib2();
|
|
32315
|
-
var ACTIVE_LOAN_LIQUIDATION_THRESHOLD_BPS = 13e3;
|
|
32316
32314
|
var EXPIRED_LOAN_MIN_LIQUIDATION_THRESHOLD_BPS = 11e3;
|
|
32317
32315
|
var GRACE_PERIOD_DAYS = 30;
|
|
32318
32316
|
var SATOSHIS_PER_BITCOIN = 100000000n;
|
|
32319
32317
|
var PRICE_ORACLE_DECIMALS = 100000000n;
|
|
32320
32318
|
var UCD_TOKEN_DECIMALS = 1000000000000000000n;
|
|
32321
|
-
var PRICE_ORACLE_OUTLIER_DEVIATION_THRESHOLD = 0.02;
|
|
32322
|
-
var PRICE_ORACLE_DISPERSION_THRESHOLD = 0.05;
|
|
32323
32319
|
var MAX_BTC_AMOUNT = 25e6 * 1e8;
|
|
32324
32320
|
var UTXO_QUERY_MAX_RETRIES = 3;
|
|
32325
32321
|
var UTXO_QUERY_RETRY_DELAY_MS = 500;
|
|
@@ -32403,7 +32399,7 @@ ${errorReport}`);
|
|
|
32403
32399
|
}
|
|
32404
32400
|
function calculateLiquidationThreshold(isExpired, daysIntoGracePeriod, activeLoanThresholdBps, maxExpiredThresholdBps) {
|
|
32405
32401
|
if (!isExpired) {
|
|
32406
|
-
return activeLoanThresholdBps
|
|
32402
|
+
return activeLoanThresholdBps;
|
|
32407
32403
|
}
|
|
32408
32404
|
const maxThreshold = maxExpiredThresholdBps ?? EXPIRED_LOAN_MIN_LIQUIDATION_THRESHOLD_BPS;
|
|
32409
32405
|
const day = Math.min(daysIntoGracePeriod, GRACE_PERIOD_DAYS);
|
|
@@ -32671,7 +32667,7 @@ ${errorReport}`);
|
|
|
32671
32667
|
positionId,
|
|
32672
32668
|
positionState.vaultAddress
|
|
32673
32669
|
),
|
|
32674
|
-
this.config.priceOracle.
|
|
32670
|
+
this.config.priceOracle.getBTCPrice()
|
|
32675
32671
|
]);
|
|
32676
32672
|
const protocolParams = createProtocolParametersModule({
|
|
32677
32673
|
termManagerAddress: this.config.termManagerAddress,
|
|
@@ -32777,7 +32773,7 @@ ${errorReport}`);
|
|
|
32777
32773
|
true
|
|
32778
32774
|
// Always skip UTXO validation for fast path
|
|
32779
32775
|
),
|
|
32780
|
-
this.config.priceOracle.
|
|
32776
|
+
this.config.priceOracle.getBTCPrice()
|
|
32781
32777
|
]);
|
|
32782
32778
|
const protocolParams = createProtocolParametersModule({
|
|
32783
32779
|
termManagerAddress: this.config.termManagerAddress,
|
|
@@ -33079,7 +33075,7 @@ ${errorReport}`);
|
|
|
33079
33075
|
*
|
|
33080
33076
|
* @param positionId - Position to check
|
|
33081
33077
|
* @param additionalDebt - Additional UCD debt to add
|
|
33082
|
-
* @param requiredRatioBps - Required collateral ratio (e.g.,
|
|
33078
|
+
* @param requiredRatioBps - Required collateral ratio (e.g., 11000 for 110%)
|
|
33083
33079
|
* @returns True if sufficient collateral exists
|
|
33084
33080
|
*/
|
|
33085
33081
|
async hasSufficientCollateral(positionId, additionalDebt, requiredRatioBps) {
|
|
@@ -33840,27 +33836,23 @@ ${errorReport}`);
|
|
|
33840
33836
|
static {
|
|
33841
33837
|
this.ACTIVE_PROVIDER_NAMES = [
|
|
33842
33838
|
"cryptocompare",
|
|
33843
|
-
"coinbase",
|
|
33844
|
-
"binance",
|
|
33845
33839
|
"coinmarketcap",
|
|
33846
33840
|
"coingecko"
|
|
33847
33841
|
];
|
|
33848
33842
|
}
|
|
33849
33843
|
static {
|
|
33850
|
-
this.
|
|
33844
|
+
this.REQUIRED_PROVIDER_COUNT = 3;
|
|
33851
33845
|
}
|
|
33852
33846
|
/**
|
|
33853
33847
|
* @param priceProvidersOrConfig - REQUIRED in production flows. An array of
|
|
33854
|
-
* `{name, apiKey}` entries
|
|
33855
|
-
* deduplicated so three entries with
|
|
33856
|
-
* single provider
|
|
33848
|
+
* exactly 3 `{name, apiKey}` entries, one per locked provider. Every entry
|
|
33849
|
+
* needs an apiKey. Names are deduplicated so three entries with
|
|
33850
|
+
* `name: "coingecko"` collapse to a single provider — which then fails the
|
|
33851
|
+
* strict count check.
|
|
33857
33852
|
* @param legacySources - Test-only back door. When supplied, the constructor
|
|
33858
33853
|
* trusts the caller-supplied array verbatim and skips credential checks.
|
|
33859
|
-
*
|
|
33860
|
-
*
|
|
33861
|
-
* @param _mode - Ignored. Previously used to branch between dev / prod
|
|
33862
|
-
* validation. The oracle no longer has a "dev" relaxation; the parameter
|
|
33863
|
-
* is kept only for backward compatibility with existing call sites.
|
|
33854
|
+
* The strict count is still enforced (exactly 3).
|
|
33855
|
+
* @param _mode - Ignored. Retained for backward-compatible call sites.
|
|
33864
33856
|
*/
|
|
33865
33857
|
constructor(priceProvidersOrConfig, legacySources, _mode) {
|
|
33866
33858
|
if (legacySources && Array.isArray(legacySources)) {
|
|
@@ -33868,7 +33860,7 @@ ${errorReport}`);
|
|
|
33868
33860
|
} else {
|
|
33869
33861
|
if (!Array.isArray(priceProvidersOrConfig)) {
|
|
33870
33862
|
throw new Error(
|
|
33871
|
-
|
|
33863
|
+
`Price oracle requires a priceProviders array \u2014 defaults and fallbacks have been removed. Pass exactly ${_PriceOracleModule.REQUIRED_PROVIDER_COUNT} distinct {name, apiKey} entries from the locked set: ` + _PriceOracleModule.ACTIVE_PROVIDER_NAMES.join(", ")
|
|
33872
33864
|
);
|
|
33873
33865
|
}
|
|
33874
33866
|
this.sources = this.buildSources(priceProvidersOrConfig);
|
|
@@ -33877,39 +33869,31 @@ ${errorReport}`);
|
|
|
33877
33869
|
this.validateProviderCount();
|
|
33878
33870
|
}
|
|
33879
33871
|
/**
|
|
33880
|
-
* Enforces
|
|
33881
|
-
*
|
|
33882
|
-
* Every caller — mint, extend, withdraw, liquidate, payment, balance — must
|
|
33883
|
-
* end up with at least {@link PriceOracleModule.MIN_DISTINCT_PROVIDERS}
|
|
33884
|
-
* distinct sources. Any relaxation here re-opens the oracle-manipulation
|
|
33885
|
-
* path flagged as H-5 in the audit.
|
|
33872
|
+
* Enforces strict 3-of-3. Any deviation re-opens the consensus-manipulation
|
|
33873
|
+
* path flagged as H-2 in the audit. There is no "≥3" or "3 of N" mode.
|
|
33886
33874
|
*/
|
|
33887
33875
|
validateProviderCount() {
|
|
33888
|
-
if (this.sources.length
|
|
33876
|
+
if (this.sources.length !== _PriceOracleModule.REQUIRED_PROVIDER_COUNT) {
|
|
33889
33877
|
throw new Error(
|
|
33890
|
-
`Price oracle requires
|
|
33878
|
+
`Price oracle requires exactly ${_PriceOracleModule.REQUIRED_PROVIDER_COUNT} providers. Currently configured: ${this.sources.length} provider(s). Locked production set: ${_PriceOracleModule.ACTIVE_PROVIDER_NAMES.join(", ")}`
|
|
33891
33879
|
);
|
|
33892
33880
|
}
|
|
33893
33881
|
}
|
|
33894
33882
|
/**
|
|
33895
33883
|
* Build price sources from the caller-supplied config.
|
|
33896
33884
|
*
|
|
33897
|
-
* Rules (all unconditional
|
|
33898
|
-
* -
|
|
33885
|
+
* Rules (all unconditional):
|
|
33886
|
+
* - Exactly 3 entries — reject fewer and reject more.
|
|
33887
|
+
* - Every entry must be a supported provider name from the locked set.
|
|
33899
33888
|
* - Every entry must carry an `apiKey`.
|
|
33900
|
-
* - Duplicates by `name` are rejected outright.
|
|
33901
|
-
* with different keys are still "one provider" from a risk standpoint
|
|
33902
|
-
* and do not satisfy the distinct-source requirement.
|
|
33903
|
-
* - The final set must contain at least 3 distinct providers.
|
|
33889
|
+
* - Duplicates by `name` are rejected outright.
|
|
33904
33890
|
*
|
|
33905
|
-
* Throws as soon as any rule is violated
|
|
33906
|
-
* entry would let the caller think consensus was achieved while the oracle
|
|
33907
|
-
* was actually running on a smaller / weaker pool.
|
|
33891
|
+
* Throws as soon as any rule is violated.
|
|
33908
33892
|
*/
|
|
33909
33893
|
buildSources(priceProviders) {
|
|
33910
|
-
if (priceProviders.length
|
|
33894
|
+
if (priceProviders.length !== _PriceOracleModule.REQUIRED_PROVIDER_COUNT) {
|
|
33911
33895
|
throw new Error(
|
|
33912
|
-
|
|
33896
|
+
`priceProviders must contain exactly ${_PriceOracleModule.REQUIRED_PROVIDER_COUNT} entries. Received: ${priceProviders.length}. Locked production set: ${_PriceOracleModule.ACTIVE_PROVIDER_NAMES.join(", ")}`
|
|
33913
33897
|
);
|
|
33914
33898
|
}
|
|
33915
33899
|
const sources = [];
|
|
@@ -33922,35 +33906,16 @@ ${errorReport}`);
|
|
|
33922
33906
|
const name = provider.name.toLowerCase();
|
|
33923
33907
|
if (!_PriceOracleModule.ACTIVE_PROVIDER_NAMES.includes(name)) {
|
|
33924
33908
|
throw new Error(
|
|
33925
|
-
`Unsupported price provider "${provider.name}".
|
|
33909
|
+
`Unsupported price provider "${provider.name}". Locked production set: ${_PriceOracleModule.ACTIVE_PROVIDER_NAMES.join(", ")}`
|
|
33926
33910
|
);
|
|
33927
33911
|
}
|
|
33928
33912
|
if (seen.has(name)) {
|
|
33929
33913
|
throw new Error(
|
|
33930
|
-
`Duplicate price provider "${name}" \u2014 the oracle requires
|
|
33914
|
+
`Duplicate price provider "${name}" \u2014 the oracle requires ${_PriceOracleModule.REQUIRED_PROVIDER_COUNT} DISTINCT providers so a single upstream failure or manipulation cannot compromise consensus. Use ${_PriceOracleModule.REQUIRED_PROVIDER_COUNT} different provider names from: ${_PriceOracleModule.ACTIVE_PROVIDER_NAMES.join(", ")}`
|
|
33931
33915
|
);
|
|
33932
33916
|
}
|
|
33933
33917
|
seen.add(name);
|
|
33934
33918
|
switch (name) {
|
|
33935
|
-
case "binance":
|
|
33936
|
-
if (!provider.apiKey) {
|
|
33937
|
-
throw new Error(
|
|
33938
|
-
"Binance provider requires an apiKey"
|
|
33939
|
-
);
|
|
33940
|
-
}
|
|
33941
|
-
sources.push(
|
|
33942
|
-
this.createBinanceSource(
|
|
33943
|
-
provider.apiKey,
|
|
33944
|
-
priority++
|
|
33945
|
-
)
|
|
33946
|
-
);
|
|
33947
|
-
break;
|
|
33948
|
-
case "coinbase":
|
|
33949
|
-
if (!provider.apiKey) {
|
|
33950
|
-
throw new Error("Coinbase provider requires an apiKey");
|
|
33951
|
-
}
|
|
33952
|
-
sources.push(this.createCoinbaseSource(provider.apiKey, priority++));
|
|
33953
|
-
break;
|
|
33954
33919
|
case "cryptocompare":
|
|
33955
33920
|
if (!provider.apiKey) {
|
|
33956
33921
|
throw new Error("CryptoCompare provider requires an apiKey");
|
|
@@ -33981,12 +33946,7 @@ ${errorReport}`);
|
|
|
33981
33946
|
throw new Error(`Unhandled provider: ${name}`);
|
|
33982
33947
|
}
|
|
33983
33948
|
}
|
|
33984
|
-
|
|
33985
|
-
throw new Error(
|
|
33986
|
-
`Insufficient price providers: need at least ${_PriceOracleModule.MIN_DISTINCT_PROVIDERS} distinct entries, got ${sources.length}.`
|
|
33987
|
-
);
|
|
33988
|
-
}
|
|
33989
|
-
return this.selectSampledSources(sources);
|
|
33949
|
+
return sources;
|
|
33990
33950
|
}
|
|
33991
33951
|
/**
|
|
33992
33952
|
* Create CryptoCompare price source
|
|
@@ -34058,21 +34018,12 @@ ${errorReport}`);
|
|
|
34058
34018
|
}
|
|
34059
34019
|
};
|
|
34060
34020
|
}
|
|
34061
|
-
selectSampledSources(sources) {
|
|
34062
|
-
return [...sources].sort((a, b2) => a.name.toLowerCase().localeCompare(b2.name.toLowerCase())).slice(0, 3).map((s, idx) => ({ ...s, priority: idx + 1 }));
|
|
34063
|
-
}
|
|
34064
34021
|
/**
|
|
34065
34022
|
* Create CoinGecko price source.
|
|
34066
34023
|
*
|
|
34067
34024
|
* CoinGecko's public endpoint has no authentication, but we intentionally
|
|
34068
34025
|
* require the caller to supply either a Demo (`x-cg-demo-api-key`) or Pro
|
|
34069
|
-
* (`x-cg-pro-api-key`) key.
|
|
34070
|
-
* - An authenticated call has a predictable rate limit and per-key quota,
|
|
34071
|
-
* so node-level retries won't silently drop under load.
|
|
34072
|
-
* - The key identifies the Diamond Hands tenant, making ETL/abuse
|
|
34073
|
-
* traceable and revokable.
|
|
34074
|
-
* - It keeps the same "every provider needs a credential" invariant
|
|
34075
|
-
* across all supported providers (removes a special case).
|
|
34026
|
+
* (`x-cg-pro-api-key`) key.
|
|
34076
34027
|
*/
|
|
34077
34028
|
createCoinGeckoSource(apiKey, priority) {
|
|
34078
34029
|
if (!apiKey) {
|
|
@@ -34098,59 +34049,6 @@ ${errorReport}`);
|
|
|
34098
34049
|
priority
|
|
34099
34050
|
};
|
|
34100
34051
|
}
|
|
34101
|
-
/**
|
|
34102
|
-
* Create Binance price source. Requires apiKey.
|
|
34103
|
-
*
|
|
34104
|
-
* The public `/ticker/price` endpoint does not require a secret; only the
|
|
34105
|
-
* API key is sent as `X-MBX-APIKEY` for per-key rate limiting and
|
|
34106
|
-
* revokability.
|
|
34107
|
-
*/
|
|
34108
|
-
createBinanceSource(apiKey, priority) {
|
|
34109
|
-
if (!apiKey) {
|
|
34110
|
-
throw new Error("createBinanceSource requires an apiKey");
|
|
34111
|
-
}
|
|
34112
|
-
const fetchJson = this.createFetchJson();
|
|
34113
|
-
return {
|
|
34114
|
-
name: "Binance",
|
|
34115
|
-
fetchPrice: async () => {
|
|
34116
|
-
const url = new URL("https://api.binance.com/api/v3/ticker/price");
|
|
34117
|
-
url.searchParams.set("symbol", "BTCUSDT");
|
|
34118
|
-
const data = await fetchJson(url.toString(), {
|
|
34119
|
-
"X-MBX-APIKEY": apiKey
|
|
34120
|
-
});
|
|
34121
|
-
const price = Number(data?.price);
|
|
34122
|
-
if (!Number.isFinite(price) || price <= 0) {
|
|
34123
|
-
throw new Error("Invalid Binance price payload");
|
|
34124
|
-
}
|
|
34125
|
-
return price;
|
|
34126
|
-
},
|
|
34127
|
-
priority
|
|
34128
|
-
};
|
|
34129
|
-
}
|
|
34130
|
-
/**
|
|
34131
|
-
* Create Coinbase price source. Requires apiKey.
|
|
34132
|
-
*/
|
|
34133
|
-
createCoinbaseSource(apiKey, priority) {
|
|
34134
|
-
if (!apiKey) {
|
|
34135
|
-
throw new Error("createCoinbaseSource requires an apiKey");
|
|
34136
|
-
}
|
|
34137
|
-
const fetchJson = this.createFetchJson();
|
|
34138
|
-
return {
|
|
34139
|
-
name: "Coinbase",
|
|
34140
|
-
fetchPrice: async () => {
|
|
34141
|
-
const data = await fetchJson(
|
|
34142
|
-
"https://api.coinbase.com/v2/prices/BTC-USDT/spot",
|
|
34143
|
-
{ "CB-ACCESS-KEY": apiKey }
|
|
34144
|
-
);
|
|
34145
|
-
const price = Number(data?.data?.amount);
|
|
34146
|
-
if (!Number.isFinite(price) || price <= 0) {
|
|
34147
|
-
throw new Error("Invalid Coinbase price payload");
|
|
34148
|
-
}
|
|
34149
|
-
return price;
|
|
34150
|
-
},
|
|
34151
|
-
priority
|
|
34152
|
-
};
|
|
34153
|
-
}
|
|
34154
34052
|
createCoinMarketCapSource(apiKey, priority) {
|
|
34155
34053
|
const fetchJson = this.createFetchJson();
|
|
34156
34054
|
return {
|
|
@@ -34175,17 +34073,21 @@ ${errorReport}`);
|
|
|
34175
34073
|
};
|
|
34176
34074
|
}
|
|
34177
34075
|
/**
|
|
34178
|
-
* Get BTC price in USD with 8 decimals
|
|
34076
|
+
* Get BTC price in USD with 8 decimals.
|
|
34179
34077
|
*
|
|
34180
|
-
*
|
|
34181
|
-
* All three
|
|
34182
|
-
* Returns the median
|
|
34078
|
+
* Strict 3-of-3: queries all sources in parallel; if any one fails, the whole
|
|
34079
|
+
* call fails (no fallback). All three prices must lie within 1% of each other
|
|
34080
|
+
* (`(hi - lo) / lo <= 0.01`). Returns the median of the three.
|
|
34081
|
+
*
|
|
34082
|
+
* This is the only signed-price path in the codebase. The previously-exposed
|
|
34083
|
+
* `getBTCPriceConsensus()` (with outlier filtering + lenient survivor median)
|
|
34084
|
+
* was removed in the H-2 fix.
|
|
34183
34085
|
*/
|
|
34184
34086
|
async getBTCPrice() {
|
|
34185
34087
|
const startTime = Date.now();
|
|
34186
|
-
if (this.sources.length !==
|
|
34088
|
+
if (this.sources.length !== _PriceOracleModule.REQUIRED_PROVIDER_COUNT) {
|
|
34187
34089
|
throw new Error(
|
|
34188
|
-
`Price oracle requires exactly
|
|
34090
|
+
`Price oracle requires exactly ${_PriceOracleModule.REQUIRED_PROVIDER_COUNT} providers. Currently configured: ${this.sources.length}`
|
|
34189
34091
|
);
|
|
34190
34092
|
}
|
|
34191
34093
|
const GLOBAL_TIMEOUT_MS = 8e3;
|
|
@@ -34222,91 +34124,6 @@ ${errorReport}`);
|
|
|
34222
34124
|
console.log(`[Price Oracle] Price with 8 decimals: ${priceWith8Decimals}`);
|
|
34223
34125
|
return priceWith8Decimals;
|
|
34224
34126
|
}
|
|
34225
|
-
/**
|
|
34226
|
-
* Consensus across multiple sources with outlier detection
|
|
34227
|
-
* Returns median price from valid sources after filtering outliers
|
|
34228
|
-
*
|
|
34229
|
-
* Master's Wisdom: Two-Path Validation
|
|
34230
|
-
* 1. If ONE source is outlier (>2% from median) → FILTER it, continue with remaining
|
|
34231
|
-
* 2. If ALL sources too dispersed (>5% spread) → REJECT all, throw error
|
|
34232
|
-
*
|
|
34233
|
-
* Logic Flow:
|
|
34234
|
-
* 1. Calculate initial median from all sources
|
|
34235
|
-
* 2. Filter individual outliers (>2% from median)
|
|
34236
|
-
* 3. If outliers found: remove them, require minimum 2 sources remaining
|
|
34237
|
-
* 4. Recalculate median from valid sources only
|
|
34238
|
-
* 5. Check if remaining sources are too dispersed (max/min ratio > 1.05)
|
|
34239
|
-
* 6. Return final median or throw appropriate error
|
|
34240
|
-
*/
|
|
34241
|
-
async getBTCPriceConsensus() {
|
|
34242
|
-
console.log(`[Price Oracle] Fetching BTC price with consensus...`);
|
|
34243
|
-
const OUTLIER_DEVIATION = PRICE_ORACLE_OUTLIER_DEVIATION_THRESHOLD;
|
|
34244
|
-
const DISPERSION_THRESHOLD = PRICE_ORACLE_DISPERSION_THRESHOLD;
|
|
34245
|
-
const results = await Promise.allSettled(
|
|
34246
|
-
this.sources.map(async (source) => {
|
|
34247
|
-
const price = await source.fetchPrice();
|
|
34248
|
-
return { source: source.name, price };
|
|
34249
|
-
})
|
|
34250
|
-
);
|
|
34251
|
-
const successful = results.filter((r) => r.status === "fulfilled").map((r) => r.value);
|
|
34252
|
-
if (successful.length === 0) {
|
|
34253
|
-
throw new Error("No price sources returned data");
|
|
34254
|
-
}
|
|
34255
|
-
console.log(
|
|
34256
|
-
`[Price Oracle] Got prices from ${successful.length}/${this.sources.length} sources:`
|
|
34257
|
-
);
|
|
34258
|
-
successful.forEach((s) => {
|
|
34259
|
-
console.log(` ${s.source}: $${s.price.toLocaleString()}`);
|
|
34260
|
-
});
|
|
34261
|
-
const prices = successful.map((s) => s.price);
|
|
34262
|
-
prices.sort((a, b2) => a - b2);
|
|
34263
|
-
const initialMedian = prices[Math.floor(prices.length / 2)];
|
|
34264
|
-
const minPrice = prices[0];
|
|
34265
|
-
const maxPrice = prices[prices.length - 1];
|
|
34266
|
-
const dispersionRatio = maxPrice / minPrice;
|
|
34267
|
-
const validPrices = successful.filter((s) => {
|
|
34268
|
-
const deviation = Math.abs(s.price - initialMedian) / initialMedian;
|
|
34269
|
-
return deviation <= OUTLIER_DEVIATION;
|
|
34270
|
-
});
|
|
34271
|
-
if (dispersionRatio > 1 + DISPERSION_THRESHOLD && validPrices.length === successful.length) {
|
|
34272
|
-
throw new Error(
|
|
34273
|
-
`Price consensus failed: sources too dispersed (${((dispersionRatio - 1) * 100).toFixed(1)}% spread)`
|
|
34274
|
-
);
|
|
34275
|
-
}
|
|
34276
|
-
if (validPrices.length < successful.length) {
|
|
34277
|
-
const outliers = successful.filter(
|
|
34278
|
-
(s) => !validPrices.find((v) => v.source === s.source)
|
|
34279
|
-
);
|
|
34280
|
-
console.log(`[Price Oracle] \u26A0\uFE0F Detected ${outliers.length} outlier(s):`);
|
|
34281
|
-
outliers.forEach((o) => {
|
|
34282
|
-
const deviation = Math.abs(o.price - initialMedian) / initialMedian;
|
|
34283
|
-
console.log(
|
|
34284
|
-
` ${o.source}: $${o.price.toLocaleString()} (${(deviation * 100).toFixed(1)}% deviation)`
|
|
34285
|
-
);
|
|
34286
|
-
});
|
|
34287
|
-
if (validPrices.length < 2) {
|
|
34288
|
-
throw new Error(
|
|
34289
|
-
"Price consensus failed: insufficient valid sources after outlier removal"
|
|
34290
|
-
);
|
|
34291
|
-
}
|
|
34292
|
-
console.log(
|
|
34293
|
-
`[Price Oracle] \u2705 Outliers filtered, continuing with ${validPrices.length} valid sources`
|
|
34294
|
-
);
|
|
34295
|
-
const validPricesOnly = validPrices.map((v) => v.price);
|
|
34296
|
-
validPricesOnly.sort((a, b2) => a - b2);
|
|
34297
|
-
const finalMedian = validPricesOnly[Math.floor(validPricesOnly.length / 2)];
|
|
34298
|
-
console.log(
|
|
34299
|
-
`[Price Oracle] \u2705 Consensus price (median): $${finalMedian.toLocaleString()}`
|
|
34300
|
-
);
|
|
34301
|
-
const priceCents2 = Math.round(finalMedian * 100);
|
|
34302
|
-
return BigInt(priceCents2) * 1000000n;
|
|
34303
|
-
}
|
|
34304
|
-
console.log(
|
|
34305
|
-
`[Price Oracle] \u2705 Consensus price (median): $${initialMedian.toLocaleString()}`
|
|
34306
|
-
);
|
|
34307
|
-
const priceCents = Math.round(initialMedian * 100);
|
|
34308
|
-
return BigInt(priceCents) * 1000000n;
|
|
34309
|
-
}
|
|
34310
34127
|
};
|
|
34311
34128
|
var VaultBalanceModule = class {
|
|
34312
34129
|
constructor(config) {
|
|
@@ -34712,30 +34529,16 @@ ${errorReport}`);
|
|
|
34712
34529
|
const oracle = params?.customSources ? new PriceOracleModule({}, params.customSources, params?.mode) : new PriceOracleModule(params?.priceProviders, void 0, params?.mode);
|
|
34713
34530
|
return await oracle.getBTCPrice();
|
|
34714
34531
|
}
|
|
34715
|
-
async function executePriceOracleConsensus(params) {
|
|
34716
|
-
global.Lit = {
|
|
34717
|
-
Actions: {
|
|
34718
|
-
broadcastAndCollect: async ({
|
|
34719
|
-
name,
|
|
34720
|
-
value
|
|
34721
|
-
}) => {
|
|
34722
|
-
return [value];
|
|
34723
|
-
}
|
|
34724
|
-
}
|
|
34725
|
-
};
|
|
34726
|
-
const oracle = params?.customSources ? new PriceOracleModule({}, params.customSources, params?.mode) : new PriceOracleModule(params?.priceProviders, void 0, params?.mode);
|
|
34727
|
-
return await oracle.getBTCPriceConsensus();
|
|
34728
|
-
}
|
|
34729
34532
|
var NOLA_EXECUTORS = {
|
|
34730
34533
|
/**
|
|
34731
34534
|
* Vault Snapshot Executor
|
|
34732
|
-
*
|
|
34535
|
+
*
|
|
34733
34536
|
* Returns complete position health metrics:
|
|
34734
34537
|
* - BTC balance (total, authorized, available)
|
|
34735
34538
|
* - Collateral ratio and liquidation risk
|
|
34736
34539
|
* - Term status (duration, expiry, grace period)
|
|
34737
34540
|
* - Protocol parameters (fees, thresholds)
|
|
34738
|
-
*
|
|
34541
|
+
*
|
|
34739
34542
|
* Cost: FREE (no LIT Action execution)
|
|
34740
34543
|
* Same data as LIT Action would return
|
|
34741
34544
|
*/
|
|
@@ -34747,39 +34550,20 @@ ${errorReport}`);
|
|
|
34747
34550
|
},
|
|
34748
34551
|
/**
|
|
34749
34552
|
* Price Oracle Executor
|
|
34750
|
-
*
|
|
34751
|
-
* Returns
|
|
34752
|
-
* -
|
|
34753
|
-
* -
|
|
34754
|
-
* -
|
|
34755
|
-
*
|
|
34756
|
-
*
|
|
34553
|
+
*
|
|
34554
|
+
* Returns BTC price in USD (8 decimals) via strict 3-of-3 consensus:
|
|
34555
|
+
* - All 3 configured providers must respond
|
|
34556
|
+
* - Prices must agree within 1%
|
|
34557
|
+
* - Returns the median
|
|
34558
|
+
*
|
|
34757
34559
|
* Cost: FREE (no LIT Action execution)
|
|
34758
34560
|
* Use for: Price display, mint preview, collateral ratio calculation
|
|
34759
34561
|
*/
|
|
34760
34562
|
priceOracle: {
|
|
34761
34563
|
name: "price-oracle",
|
|
34762
|
-
description: "Get current BTC price (
|
|
34564
|
+
description: "Get current BTC price (strict 3-of-3 consensus)",
|
|
34763
34565
|
executor: executePriceOracle,
|
|
34764
|
-
version: "
|
|
34765
|
-
},
|
|
34766
|
-
/**
|
|
34767
|
-
* Price Oracle Consensus Executor
|
|
34768
|
-
*
|
|
34769
|
-
* Returns BTC price using multi-source consensus:
|
|
34770
|
-
* - Queries ALL configured sources
|
|
34771
|
-
* - Filters outliers (>2% deviation from median)
|
|
34772
|
-
* - Returns median of valid sources
|
|
34773
|
-
* - Rejects if sources too dispersed (>5% spread)
|
|
34774
|
-
*
|
|
34775
|
-
* Cost: FREE (no LIT Action execution)
|
|
34776
|
-
* Use for: High-stakes operations requiring price validation
|
|
34777
|
-
*/
|
|
34778
|
-
priceOracleConsensus: {
|
|
34779
|
-
name: "price-oracle-consensus",
|
|
34780
|
-
description: "Get BTC price with multi-source consensus",
|
|
34781
|
-
executor: executePriceOracleConsensus,
|
|
34782
|
-
version: "1.0.0"
|
|
34566
|
+
version: "2.0.0"
|
|
34783
34567
|
}
|
|
34784
34568
|
};
|
|
34785
34569
|
}
|
|
@@ -112320,16 +112104,17 @@ var BitcoinOperations = class {
|
|
|
112320
112104
|
return { verified: false, reason: "not yet visible after retries" };
|
|
112321
112105
|
}
|
|
112322
112106
|
/**
|
|
112323
|
-
* Get current BTC price using LIT Protocol price oracle
|
|
112107
|
+
* Get current BTC price using LIT Protocol price oracle.
|
|
112324
112108
|
*
|
|
112325
|
-
*
|
|
112326
|
-
*
|
|
112109
|
+
* Strict 3-of-3: all three configured providers must respond within 1% of
|
|
112110
|
+
* each other, and the median is returned. The previous `mode: "fast" | "full"`
|
|
112111
|
+
* parameter (with single-source and lenient-consensus variants) was removed
|
|
112112
|
+
* in the H-2 audit fix — there is only one strict path now.
|
|
112327
112113
|
*
|
|
112328
|
-
* @param mode - Price fetch mode: "fast" (single source) or "full" (consensus)
|
|
112329
112114
|
* @param sign - Whether to request PKP signature on the price
|
|
112330
112115
|
* @returns BTC price result with timestamp and source
|
|
112331
112116
|
*/
|
|
112332
|
-
async getPrice(
|
|
112117
|
+
async getPrice(sign = false) {
|
|
112333
112118
|
if (!this.litOps) {
|
|
112334
112119
|
return failure(
|
|
112335
112120
|
new SDKError({
|
|
@@ -112344,13 +112129,11 @@ var BitcoinOperations = class {
|
|
|
112344
112129
|
async () => {
|
|
112345
112130
|
if (this.config.debug) {
|
|
112346
112131
|
log.info("\u{1F4B0} Fetching BTC price via LIT Protocol oracle", {
|
|
112347
|
-
mode,
|
|
112348
112132
|
sign,
|
|
112349
112133
|
hasSigner: !!this.config.signer
|
|
112350
112134
|
});
|
|
112351
112135
|
}
|
|
112352
112136
|
const result = await this.litOps.getBTCPrice({
|
|
112353
|
-
mode,
|
|
112354
112137
|
sign,
|
|
112355
112138
|
signer: this.config.signer,
|
|
112356
112139
|
pkpId: this.config.priceOraclePkpId,
|
|
@@ -112388,7 +112171,6 @@ var BitcoinOperations = class {
|
|
|
112388
112171
|
try {
|
|
112389
112172
|
const litOpsConfig = this.litOps?.getConfig?.() || {};
|
|
112390
112173
|
log.error("\u274C BTC price oracle failed", {
|
|
112391
|
-
mode,
|
|
112392
112174
|
sign,
|
|
112393
112175
|
errorMessage: error2 instanceof Error ? error2.message : String(error2),
|
|
112394
112176
|
errorStack: error2 instanceof Error ? error2.stack : void 0,
|
|
@@ -112405,7 +112187,6 @@ var BitcoinOperations = class {
|
|
|
112405
112187
|
severity: "MEDIUM" /* MEDIUM */,
|
|
112406
112188
|
originalError: error2 instanceof Error ? error2 : new Error(String(error2)),
|
|
112407
112189
|
context: {
|
|
112408
|
-
mode,
|
|
112409
112190
|
sign,
|
|
112410
112191
|
serviceEndpoint: this.litOps?.getConfig?.()?.serviceEndpoint,
|
|
112411
112192
|
network: this.litOps?.getConfig?.()?.network
|
|
@@ -122772,7 +122553,7 @@ Error data: ${errorData || "none"}`
|
|
|
122772
122553
|
source: json.data.source
|
|
122773
122554
|
};
|
|
122774
122555
|
}
|
|
122775
|
-
const result = await this.bitcoinOperations.getPrice(
|
|
122556
|
+
const result = await this.bitcoinOperations.getPrice(false);
|
|
122776
122557
|
if (!result.success) {
|
|
122777
122558
|
const cause = result.error?.originalError?.message ?? String(result.error);
|
|
122778
122559
|
throw new Error(`Failed to get BTC price: ${cause}`);
|