@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/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: "QmNgE555xr7SGduoJWXk8oLMPiKCT3xYdDg7uCWLVp6Ewk",
31400
+ cid: "QmWZJpS3Q25XKo9ptzVcYz7pnW5hbqhuSvrhu7Qo7EcxEk",
31402
31401
  authorizedCidHex: cidToHex(
31403
- "QmNgE555xr7SGduoJWXk8oLMPiKCT3xYdDg7uCWLVp6Ewk"
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: 1779894180903,
31410
- size: 69530,
31411
- hash: "64e45e5a1918af2e375f12e5036757364080a15b640e8b7d76b513109c1e0b3c",
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: "QmVmgq1zAuwdiyYsBx9LoUZFJetz2qC7EAjjwB55Yb3ZPJ",
31418
+ cid: "QmRZjMcJzEAzepwN3uJBbgGxMPULvCw6LMpQ94w19sv3Cx",
31420
31419
  authorizedCidHex: cidToHex(
31421
- "QmVmgq1zAuwdiyYsBx9LoUZFJetz2qC7EAjjwB55Yb3ZPJ"
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: 1779894189375,
31428
- size: 65519,
31429
- hash: "cc3d394347166f9611bdb780f0dfcabea0d5e6fe21ebfddd1b481432e59e0d8d",
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: "QmSVjVq18N2mzhrjxCLs1UGFqAD4TLwG6CEGZzCFSb4GoZ",
31436
+ cid: "Qmb4y62Ftjar5EXcREyXC84U7QEMhCQgycHYCmJxLichvt",
31438
31437
  authorizedCidHex: cidToHex(
31439
- "QmSVjVq18N2mzhrjxCLs1UGFqAD4TLwG6CEGZzCFSb4GoZ"
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: 1779894197740,
31446
- size: 64948,
31447
- hash: "97cdc90fa70e4dfb3c64b073bb22257c3a696d3392e3cca3b4d7ae7304751845",
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: "QmWBZxCTXP52fxakJRRQ4wiDwF9AS4E5RJXtRinnaShbtu",
31454
+ cid: "QmetrNkAUQ54PHzHLRR7TfDk3oGKnCf22m2bQwj24eB253",
31456
31455
  authorizedCidHex: cidToHex(
31457
- "QmWBZxCTXP52fxakJRRQ4wiDwF9AS4E5RJXtRinnaShbtu"
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: 1779894206894,
31464
- size: 76209,
31465
- hash: "ac5756d09e0a4f04513af18fdb6f3054ebd0bcb61bc51e8de7c98049b1a296c3",
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: "QmcQAWj3nCsAbHkqBnBnk6LzqKEvVy7Ed5awnTQ9s9Nznq",
31472
+ cid: "QmRuLKJmsD8yN6Ez89L9mzSM3zyarjGwFMBwn23CkajizZ",
31474
31473
  authorizedCidHex: cidToHex(
31475
- "QmcQAWj3nCsAbHkqBnBnk6LzqKEvVy7Ed5awnTQ9s9Nznq"
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: 1779894215050,
31482
- size: 56114,
31483
- hash: "b0fcc1acfbf40e4e77de2d3327447e691b0e4a82fe0b34bd8d47d1c6051e9766",
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: "QmYvwgGkFcvkqFB93oebMRDeqFgiHBAxRUcd6qKgktqXAf",
31490
+ cid: "QmR5mjqhxfEPuBMbxhcXkJpdAMDzYfkpUWPgcPNCiSuhqh",
31492
31491
  authorizedCidHex: cidToHex(
31493
- "QmYvwgGkFcvkqFB93oebMRDeqFgiHBAxRUcd6qKgktqXAf"
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: 1779199116800,
31500
- size: 11179,
31501
- hash: "83102b059588020143ca5fbc0f651318fa1436914a6236e356758c8d31468a78",
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: "QmWqHBGzyhQB4Usfs47W7nGGYsCivJXFaJQCRqoPE8hy6i",
31508
+ cid: "QmbXoFbhtqWsgKkLxtxwd6fDuKvvBpPhpMmdqUU1UC9GMn",
31510
31509
  authorizedCidHex: cidToHex(
31511
- "QmWqHBGzyhQB4Usfs47W7nGGYsCivJXFaJQCRqoPE8hy6i"
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: 1779894223069,
31518
- size: 45960,
31519
- hash: "7ee25d0058e7f9f50f7c97f966cbbea46c53e3e08891d0403b41223ddaf03a5f",
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 ?? ACTIVE_LOAN_LIQUIDATION_THRESHOLD_BPS;
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.getBTCPriceConsensus()
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.getBTCPriceConsensus()
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., 13000 for 130%)
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.MIN_DISTINCT_PROVIDERS = 3;
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. Every provider needs an apiKey. Names are
33855
- * deduplicated so three entries with `name: "coingecko"` collapse to a
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
- * This path is exercised exclusively by unit tests that inject in-process
33860
- * `fetchPrice` stubs.
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
- "Price oracle requires a priceProviders array \u2014 defaults and fallbacks have been removed. Pass 3 distinct {name, apiKey} entries from the supported set: " + _PriceOracleModule.ACTIVE_PROVIDER_NAMES.join(", ")
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 the unconditional, mode-independent 3-provider rule.
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 < _PriceOracleModule.MIN_DISTINCT_PROVIDERS) {
33876
+ if (this.sources.length !== _PriceOracleModule.REQUIRED_PROVIDER_COUNT) {
33889
33877
  throw new Error(
33890
- `Price oracle requires at least ${_PriceOracleModule.MIN_DISTINCT_PROVIDERS} eligible providers for consensus. Currently configured: ${this.sources.length} provider(s). Supported active providers: ${_PriceOracleModule.ACTIVE_PROVIDER_NAMES.join(", ")}`
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 — there is no dev-mode relaxation):
33898
- * - Every entry must be a supported provider name.
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. Three CoinGecko entries
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 — silently dropping an invalid
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 === 0) {
33894
+ if (priceProviders.length !== _PriceOracleModule.REQUIRED_PROVIDER_COUNT) {
33911
33895
  throw new Error(
33912
- "priceProviders must be a non-empty array of 3 distinct providers, each with an apiKey."
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}". Supported: ${_PriceOracleModule.ACTIVE_PROVIDER_NAMES.join(", ")}`
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 3 DISTINCT providers so a single upstream failure or manipulation cannot compromise consensus. Use 3 different provider names from: ${_PriceOracleModule.ACTIVE_PROVIDER_NAMES.join(", ")}`
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
- if (sources.length < _PriceOracleModule.MIN_DISTINCT_PROVIDERS) {
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. Reasons:
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
- * CRITICAL OPTIMIZATION: Queries all sources in parallel with Promise.race()
34181
- * All three providers must resolve and agree within 1% tolerance.
34182
- * Returns the median price.
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 !== 3) {
34088
+ if (this.sources.length !== _PriceOracleModule.REQUIRED_PROVIDER_COUNT) {
34187
34089
  throw new Error(
34188
- `Price oracle requires exactly 3 providers. Currently configured: ${this.sources.length}`
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 current BTC price in USD with 8 decimals:
34752
- * - Queries CoinGecko, Binance, Coinbase in parallel
34753
- * - First successful response wins (fastest path)
34754
- * - Automatic fallback if primary source fails
34755
- * - Same price format as LIT Action validator
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 (fastest source)",
34564
+ description: "Get current BTC price (strict 3-of-3 consensus)",
34763
34565
  executor: executePriceOracle,
34764
- version: "1.0.0"
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
- * Queries the decentralized price oracle via LIT Actions.
112326
- * Supports fast mode (single source) and full mode (consensus).
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(mode = "fast", sign = false) {
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("fast", false);
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}`);