@gvnrdao/dh-lit-actions 0.0.27 → 0.0.29

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.
@@ -1 +1 @@
1
- 873cdfb66ff07727655c6066bbea5b8b20a9c336f6d28901caa9dfc9fd14baa2
1
+ e8e09a379fce1f039c3cd593d07b5bade9acb509d4ef93aec46a2a4dda27f346
@@ -11,10 +11,6 @@ var _LIT_ACTION_ = (() => {
11
11
  var PRICE_ORACLE_DECIMALS = 100000000n;
12
12
  var UCD_TOKEN_DECIMALS = 1000000000000000000n;
13
13
 
14
- // src/constants/chunks/price-oracle.ts
15
- var PRICE_ORACLE_OUTLIER_DEVIATION_THRESHOLD = 0.02;
16
- var PRICE_ORACLE_DISPERSION_THRESHOLD = 0.05;
17
-
18
14
  // src/constants/chunks/bitcoin.ts
19
15
  var BITCOIN_DEFAULT_MIN_CONFIRMATIONS = 6;
20
16
 
@@ -230,43 +226,6 @@ var _LIT_ACTION_ = (() => {
230
226
  function getQuantumStart(timestamp) {
231
227
  return Math.floor(timestamp / QUANTUM_WINDOW_SECONDS) * QUANTUM_WINDOW_SECONDS;
232
228
  }
233
- function getCurrentQuantumTimestamp() {
234
- const now = Math.floor(Date.now() / 1e3);
235
- return getQuantumStart(now);
236
- }
237
- function isInDeadZone(now) {
238
- const currentTime = now ?? Math.floor(Date.now() / 1e3);
239
- const timeInQuantum = currentTime % QUANTUM_WINDOW_SECONDS;
240
- return timeInQuantum >= 92 || timeInQuantum < 8;
241
- }
242
- async function waitForSafeQuantumMoment() {
243
- const now = Math.floor(Date.now() / 1e3);
244
- const timeInQuantum = now % QUANTUM_WINDOW_SECONDS;
245
- if (!isInDeadZone(now)) {
246
- return;
247
- }
248
- let waitSeconds;
249
- if (timeInQuantum >= 92) {
250
- waitSeconds = 100 - timeInQuantum + 8;
251
- } else {
252
- waitSeconds = 8 - timeInQuantum;
253
- }
254
- console.log(
255
- `[Quantum] Waiting ${waitSeconds}s for safe moment (current time in quantum: ${timeInQuantum}s)`
256
- );
257
- await new Promise((resolve) => setTimeout(resolve, waitSeconds * 1e3));
258
- console.log(`[Quantum] Safe quantum ready: ${getCurrentQuantumTimestamp()}`);
259
- }
260
- function validateQuantumTimestamp(timestampOnSignature, now) {
261
- const currentTime = now ?? Math.floor(Date.now() / 1e3);
262
- const currentQuantum = getQuantumStart(currentTime);
263
- const signatureQuantum = getQuantumStart(timestampOnSignature);
264
- if (signatureQuantum !== currentQuantum) {
265
- throw new Error(
266
- `[Quantum] Invalid timestamp: signature from quantum ${signatureQuantum}, current quantum is ${currentQuantum}`
267
- );
268
- }
269
- }
270
229
 
271
230
  // src/modules/authorization.module.ts
272
231
  var AuthorizationModule = class {
@@ -287,9 +246,26 @@ var _LIT_ACTION_ = (() => {
287
246
  * @returns True if authorized
288
247
  */
289
248
  static async verifyOwnerSignature(litActionName, auth, expectedOwner, actionParams) {
290
- await waitForSafeQuantumMoment();
291
249
  try {
292
- validateQuantumTimestamp(auth.timestamp);
250
+ const now = Math.floor(Date.now() / 1e3);
251
+ const currentQuantum = getQuantumStart(now);
252
+ const signatureQuantum = getQuantumStart(auth.timestamp);
253
+ const previousQuantum = currentQuantum - QUANTUM_WINDOW_SECONDS;
254
+ const previousQuantum2 = previousQuantum - QUANTUM_WINDOW_SECONDS;
255
+ if (signatureQuantum !== currentQuantum && signatureQuantum !== previousQuantum && signatureQuantum !== previousQuantum2) {
256
+ console.error(
257
+ "[Authorization] Quantum timestamp outside allowed window:",
258
+ `
259
+ Signature quantum: ${signatureQuantum}`,
260
+ `
261
+ Current quantum: ${currentQuantum}`,
262
+ `
263
+ Previous quantum: ${previousQuantum}`,
264
+ `
265
+ Previous-2 quantum: ${previousQuantum2}`
266
+ );
267
+ return false;
268
+ }
293
269
  } catch (error) {
294
270
  console.error(
295
271
  "[Authorization] Quantum timestamp validation failed:",
@@ -413,7 +389,11 @@ var _LIT_ACTION_ = (() => {
413
389
  positionOwner,
414
390
  {
415
391
  action: ethers.utils.keccak256(ethers.utils.toUtf8Bytes("mintUCD")),
416
- amount: ethers.utils.hexZeroPad(ethers.utils.hexlify(amount), 32)
392
+ // Normalize amount to a consistent 32-byte hex for signing regardless of input type
393
+ amount: ethers.utils.hexZeroPad(
394
+ ethers.utils.hexlify(ethers.BigNumber.from(amount)),
395
+ 32
396
+ )
417
397
  }
418
398
  );
419
399
  }
@@ -475,7 +455,9 @@ var _LIT_ACTION_ = (() => {
475
455
  * @returns Array of UTXOs
476
456
  */
477
457
  async getUTXOs(address) {
458
+ console.log(`[Bitcoin Data] Original address: "${address}"`);
478
459
  const cleanAddress = this.stripNetworkPrefix(address);
460
+ console.log(`[Bitcoin Data] Cleaned address: "${cleanAddress}"`);
479
461
  if (this.config.rpcHelper) {
480
462
  return await this.fetchUTXOsFromRPC(cleanAddress);
481
463
  }
@@ -615,6 +597,7 @@ var _LIT_ACTION_ = (() => {
615
597
  } else {
616
598
  endpoint = `${providerUrl}/address/${address}/utxos`;
617
599
  }
600
+ console.log(`Fetching UTXOs from ${endpoint}`);
618
601
  const controller = new AbortController();
619
602
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
620
603
  try {
@@ -626,6 +609,7 @@ var _LIT_ACTION_ = (() => {
626
609
  );
627
610
  }
628
611
  const data = await response.json();
612
+ console.log(`[Line 222 Context] Raw API Response:`, JSON.stringify(data, null, 2));
629
613
  if (providerName === "Diamond Hands") {
630
614
  return this.parseDiamondHandsFaucetUTXOs(data);
631
615
  } else {
@@ -739,6 +723,23 @@ var _LIT_ACTION_ = (() => {
739
723
  this.sources.sort((a, b) => a.priority - b.priority);
740
724
  }
741
725
  getDefaultSources() {
726
+ const DEFAULT_HEADERS = {
727
+ "User-Agent": "diamond-hands-lit-action/1.0",
728
+ Accept: "application/json"
729
+ };
730
+ const fetchJson = async (url) => {
731
+ const controller = new AbortController();
732
+ const id = setTimeout(() => controller.abort(), 8e3);
733
+ try {
734
+ const res = await fetch(url, { headers: DEFAULT_HEADERS, signal: controller.signal });
735
+ if (!res.ok) {
736
+ throw new Error(`HTTP ${res.status} ${res.statusText}`);
737
+ }
738
+ return await res.json();
739
+ } finally {
740
+ clearTimeout(id);
741
+ }
742
+ };
742
743
  return [
743
744
  {
744
745
  name: "CoinGecko",
@@ -746,12 +747,11 @@ var _LIT_ACTION_ = (() => {
746
747
  const url = new URL("https://api.coingecko.com/api/v3/simple/price");
747
748
  url.searchParams.set("ids", "bitcoin");
748
749
  url.searchParams.set("vs_currencies", "usd");
749
- const response = await fetch(url.toString());
750
- if (!response.ok) {
751
- throw new Error(`CoinGecko API error: ${response.status} ${response.statusText}`);
750
+ const data = await fetchJson(url.toString());
751
+ const price = Number(data?.bitcoin?.usd);
752
+ if (!Number.isFinite(price) || price <= 0) {
753
+ throw new Error("Invalid CoinGecko price payload");
752
754
  }
753
- const data = await response.json();
754
- const price = data.bitcoin.usd;
755
755
  const allPrices = await Lit.Actions.broadcastAndCollect({
756
756
  name: "coinGeckoPrice",
757
757
  value: price.toString()
@@ -767,12 +767,11 @@ var _LIT_ACTION_ = (() => {
767
767
  fetchPrice: async () => {
768
768
  const url = new URL("https://api.binance.com/api/v3/ticker/price");
769
769
  url.searchParams.set("symbol", "BTCUSDT");
770
- const response = await fetch(url.toString());
771
- if (!response.ok) {
772
- throw new Error(`Binance API error: ${response.status} ${response.statusText}`);
770
+ const data = await fetchJson(url.toString());
771
+ const price = Number(data?.price);
772
+ if (!Number.isFinite(price) || price <= 0) {
773
+ throw new Error("Invalid Binance price payload");
773
774
  }
774
- const data = await response.json();
775
- const price = parseFloat(data.price);
776
775
  const allPrices = await Lit.Actions.broadcastAndCollect({
777
776
  name: "binancePrice",
778
777
  value: price.toString()
@@ -786,12 +785,11 @@ var _LIT_ACTION_ = (() => {
786
785
  {
787
786
  name: "Coinbase",
788
787
  fetchPrice: async () => {
789
- const response = await fetch("https://api.coinbase.com/v2/prices/BTC-USD/spot");
790
- if (!response.ok) {
791
- throw new Error(`Coinbase API error: ${response.status} ${response.statusText}`);
788
+ const data = await fetchJson("https://api.coinbase.com/v2/prices/BTC-USD/spot");
789
+ const price = Number(data?.data?.amount);
790
+ if (!Number.isFinite(price) || price <= 0) {
791
+ throw new Error("Invalid Coinbase price payload");
792
792
  }
793
- const data = await response.json();
794
- const price = parseFloat(data.data.amount);
795
793
  const allPrices = await Lit.Actions.broadcastAndCollect({
796
794
  name: "coinbasePrice",
797
795
  value: price.toString()
@@ -849,6 +847,8 @@ var _LIT_ACTION_ = (() => {
849
847
  */
850
848
  async getBTCPriceConsensus() {
851
849
  console.log(`[Price Oracle] Fetching BTC price with consensus...`);
850
+ const OUTLIER_DEVIATION = 5e-3;
851
+ const DISPERSION_THRESHOLD = 0.05;
852
852
  const results = await Promise.allSettled(
853
853
  this.sources.map(async (source) => {
854
854
  const price = await source.fetchPrice();
@@ -873,9 +873,9 @@ var _LIT_ACTION_ = (() => {
873
873
  const dispersionRatio = maxPrice / minPrice;
874
874
  const validPrices = successful.filter((s) => {
875
875
  const deviation = Math.abs(s.price - initialMedian) / initialMedian;
876
- return deviation <= PRICE_ORACLE_OUTLIER_DEVIATION_THRESHOLD;
876
+ return deviation <= OUTLIER_DEVIATION;
877
877
  });
878
- if (dispersionRatio > 1 + PRICE_ORACLE_DISPERSION_THRESHOLD && validPrices.length === successful.length) {
878
+ if (dispersionRatio > 1 + DISPERSION_THRESHOLD && validPrices.length === successful.length) {
879
879
  throw new Error(
880
880
  `Price consensus failed: sources too dispersed (${((dispersionRatio - 1) * 100).toFixed(1)}% spread)`
881
881
  );
@@ -1261,24 +1261,21 @@ var _LIT_ACTION_ = (() => {
1261
1261
  * @returns Liquidation threshold in basis points
1262
1262
  */
1263
1263
  async getLiquidationThreshold() {
1264
- const abi = [
1265
- {
1266
- inputs: [],
1267
- name: "liquidationThreshold",
1268
- outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
1269
- stateMutability: "view",
1270
- type: "function"
1271
- }
1272
- ];
1273
1264
  try {
1274
- const result = await Lit.Actions.call({
1275
- chain: this.chain,
1276
- contractAddress: this.loanOpsManagerAddress,
1277
- abi,
1278
- methodName: "liquidationThreshold",
1279
- params: []
1280
- });
1281
- return Number(result);
1265
+ const rpcUrl = await Lit.Actions.getRpcUrl({ chain: this.chain });
1266
+ const provider = new ethers.providers.JsonRpcProvider(rpcUrl);
1267
+ const abi = [
1268
+ {
1269
+ inputs: [],
1270
+ name: "liquidationThreshold",
1271
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
1272
+ stateMutability: "view",
1273
+ type: "function"
1274
+ }
1275
+ ];
1276
+ const contract = new ethers.Contract(this.loanOpsManagerAddress, abi, provider);
1277
+ const result = await contract.liquidationThreshold();
1278
+ return Number(result.toString());
1282
1279
  } catch (error) {
1283
1280
  console.error(
1284
1281
  "[ProtocolParameters] Error fetching liquidation threshold:",
@@ -1296,31 +1293,28 @@ var _LIT_ACTION_ = (() => {
1296
1293
  * @returns Term fees (origination and extension) in basis points
1297
1294
  */
1298
1295
  async getTermFees(termMonths) {
1299
- const abi = [
1300
- {
1301
- inputs: [
1302
- { internalType: "uint256", name: "_termMonths", type: "uint256" }
1303
- ],
1304
- name: "getTermFees",
1305
- outputs: [
1306
- { internalType: "uint88", name: "originationFee", type: "uint88" },
1307
- { internalType: "uint88", name: "extensionFee", type: "uint88" }
1308
- ],
1309
- stateMutability: "view",
1310
- type: "function"
1311
- }
1312
- ];
1313
1296
  try {
1314
- const result = await Lit.Actions.call({
1315
- chain: this.chain,
1316
- contractAddress: this.termManagerAddress,
1317
- abi,
1318
- methodName: "getTermFees",
1319
- params: [termMonths]
1320
- });
1297
+ const rpcUrl = await Lit.Actions.getRpcUrl({ chain: this.chain });
1298
+ const provider = new ethers.providers.JsonRpcProvider(rpcUrl);
1299
+ const abi = [
1300
+ {
1301
+ inputs: [
1302
+ { internalType: "uint256", name: "_termMonths", type: "uint256" }
1303
+ ],
1304
+ name: "getTermFees",
1305
+ outputs: [
1306
+ { internalType: "uint88", name: "originationFee", type: "uint88" },
1307
+ { internalType: "uint88", name: "extensionFee", type: "uint88" }
1308
+ ],
1309
+ stateMutability: "view",
1310
+ type: "function"
1311
+ }
1312
+ ];
1313
+ const contract = new ethers.Contract(this.termManagerAddress, abi, provider);
1314
+ const result = await contract.getTermFees(termMonths);
1321
1315
  return {
1322
- originationFeeBps: Number(result[0]),
1323
- extensionFeeBps: Number(result[1])
1316
+ originationFeeBps: Number(result.originationFee?.toString?.() ?? result[0]?.toString?.() ?? result[0]),
1317
+ extensionFeeBps: Number(result.extensionFee?.toString?.() ?? result[1]?.toString?.() ?? result[1])
1324
1318
  };
1325
1319
  } catch (error) {
1326
1320
  console.error(
@@ -1351,6 +1345,7 @@ var _LIT_ACTION_ = (() => {
1351
1345
  */
1352
1346
  async getVaultSnapshot(positionId) {
1353
1347
  const positionState = await this.queryPositionState(positionId);
1348
+ console.log(`[Vault Snapshot] Raw vault address from contract: "${positionState.vaultAddress}"`);
1354
1349
  const balanceResult = await this.config.vaultBalance.calculateTrustedBalance(
1355
1350
  positionId,
1356
1351
  positionState.vaultAddress
@@ -2108,6 +2103,7 @@ var _LIT_ACTION_ = (() => {
2108
2103
  "bytes32",
2109
2104
  "bytes32",
2110
2105
  "bytes32",
2106
+ "bytes32",
2111
2107
  "uint256"
2112
2108
  ],
2113
2109
  [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gvnrdao/dh-lit-actions",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
4
4
  "type": "module",
5
5
  "description": "Diamond Hands Protocol LIT Actions - Deterministic, Auditable Builds",
6
6
  "main": "./pkg-dist/index.cjs",
@@ -17,7 +17,7 @@ exports.DH_LIT_ACTIONS_DATIL = {
17
17
  description: "Production authorization LIT Action for Milestone 1 testing and PKP authorization",
18
18
  version: "0.1.0",
19
19
  deployed: true,
20
- deployedAt: 1761413462458,
20
+ deployedAt: 1761427363916,
21
21
  size: 1016,
22
22
  hash: "c732ef30e50a5013a6c1cbac6dc011d3638875237d21097e3aff722b323d174b",
23
23
  },
@@ -28,7 +28,7 @@ exports.DH_LIT_ACTIONS_DATIL = {
28
28
  description: "Production second dummy authorization LIT Action for testing failed authorization scenarios",
29
29
  version: "0.1.0",
30
30
  deployed: true,
31
- deployedAt: 1761413462458,
31
+ deployedAt: 1761427363915,
32
32
  size: 723,
33
33
  hash: "6262c9467961c661d212b8c60806e499ed5e7d0fe8456e2455e536d40eb4c672",
34
34
  },
@@ -43,7 +43,7 @@ exports.DH_LIT_ACTIONS_DATIL = {
43
43
  size: 12322,
44
44
  hash: "ac5d1dbc1ae8b678f435ac568320887e69e662d93d5f92e11f69e3a322f2e1ef",
45
45
  pkp: {
46
- tokenId: "999461970",
46
+ tokenId: "999363399",
47
47
  publicKey: "0x0411111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
48
48
  ethAddress: "0x1111111111111111111111111111111111111111",
49
49
  mintTxHash: "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
@@ -51,19 +51,19 @@ exports.DH_LIT_ACTIONS_DATIL = {
51
51
  burnTxHash: "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
52
52
  immutable: true,
53
53
  authorizedCidHex: "0x1220cd432b9afffbf6595071b32888cfe7dd49b571c0afc0c1bea290cdf02e2b66c5",
54
- createdAt: 1761413461970,
54
+ createdAt: 1761427363400,
55
55
  },
56
56
  },
57
57
  ucdMintValidator: {
58
- cid: "QmTmvtVDVVac31CDjJJtQJKUoehE3iCDw6fUUFfsoneiDq", // Placeholder - needs IPFS deployment
58
+ cid: "QmSZQoeajkKiwNrtccpaPBRehxX5hQtnusJPDnGAKcbVSk", // Placeholder - needs IPFS deployment
59
59
  authorizedCidHex: (0, cid_utils_1.cidToHex)("QmNLei78zWmzUdbeRB3CiUfAizWUrbeeZh5K1rhAQKCh51"),
60
60
  name: "UCD Mint Validator",
61
61
  description: "Production UCD mint validator LIT Action for validating mint operations with comprehensive on-chain checks",
62
62
  version: "0.1.0",
63
63
  deployed: true, // Not yet deployed to IPFS
64
- deployedAt: 1761413462459,
65
- size: 34828,
66
- hash: "6c842ec61916b48d7a77ad2ecf7a3567e0c33fd20c3870f8ce97f296f3e4a1a9",
64
+ deployedAt: 1761427363917,
65
+ size: 35512,
66
+ hash: "873cdfb66ff07727655c6066bbea5b8b20a9c336f6d28901caa9dfc9fd14baa2",
67
67
  pkp: {
68
68
  tokenId: "0",
69
69
  publicKey: "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
@@ -86,7 +86,7 @@ exports.DH_LIT_ACTIONS_DATIL_TEST = {
86
86
  description: "Development authorization LIT Action for Milestone 1 testing and PKP authorization on datil-test",
87
87
  version: "0.1.0",
88
88
  deployed: true,
89
- deployedAt: 1761413462458, // Earlier deployment
89
+ deployedAt: 1761427363916, // Earlier deployment
90
90
  size: 1016,
91
91
  hash: "c732ef30e50a5013a6c1cbac6dc011d3638875237d21097e3aff722b323d174b",
92
92
  },
@@ -97,7 +97,7 @@ exports.DH_LIT_ACTIONS_DATIL_TEST = {
97
97
  description: "Development second dummy authorization LIT Action for testing failed authorization scenarios on datil-test",
98
98
  version: "0.1.0",
99
99
  deployed: true, // Not yet deployed to test network
100
- deployedAt: 1761413462458,
100
+ deployedAt: 1761427363915,
101
101
  size: 723,
102
102
  hash: "6262c9467961c661d212b8c60806e499ed5e7d0fe8456e2455e536d40eb4c672",
103
103
  },
@@ -112,7 +112,7 @@ exports.DH_LIT_ACTIONS_DATIL_TEST = {
112
112
  size: 12322,
113
113
  hash: "ac5d1dbc1ae8b678f435ac568320887e69e662d93d5f92e11f69e3a322f2e1ef",
114
114
  pkp: {
115
- tokenId: "999461970",
115
+ tokenId: "999363399",
116
116
  publicKey: "0x0411111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
117
117
  ethAddress: "0x1111111111111111111111111111111111111111",
118
118
  mintTxHash: "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
@@ -120,19 +120,19 @@ exports.DH_LIT_ACTIONS_DATIL_TEST = {
120
120
  burnTxHash: "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
121
121
  immutable: true,
122
122
  authorizedCidHex: "0x1220cd432b9afffbf6595071b32888cfe7dd49b571c0afc0c1bea290cdf02e2b66c5",
123
- createdAt: 1761413461970,
123
+ createdAt: 1761427363400,
124
124
  },
125
125
  },
126
126
  ucdMintValidator: {
127
- cid: "QmTmvtVDVVac31CDjJJtQJKUoehE3iCDw6fUUFfsoneiDq", // Placeholder - needs IPFS deployment
127
+ cid: "QmSZQoeajkKiwNrtccpaPBRehxX5hQtnusJPDnGAKcbVSk", // Placeholder - needs IPFS deployment
128
128
  authorizedCidHex: (0, cid_utils_1.cidToHex)("QmNLei78zWmzUdbeRB3CiUfAizWUrbeeZh5K1rhAQKCh51"),
129
129
  name: "UCD Mint Validator (Test)",
130
130
  description: "Development UCD mint validator LIT Action for validating mint operations with comprehensive on-chain checks on datil-test",
131
131
  version: "0.1.0",
132
132
  deployed: true, // Not yet deployed to IPFS
133
- deployedAt: 1761413462459,
134
- size: 34828,
135
- hash: "6c842ec61916b48d7a77ad2ecf7a3567e0c33fd20c3870f8ce97f296f3e4a1a9",
133
+ deployedAt: 1761427363917,
134
+ size: 35512,
135
+ hash: "873cdfb66ff07727655c6066bbea5b8b20a9c336f6d28901caa9dfc9fd14baa2",
136
136
  pkp: {
137
137
  tokenId: "0",
138
138
  publicKey: "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",