@lucid-evolution/utils 0.1.75 → 0.1.76

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.cjs CHANGED
@@ -32,6 +32,7 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  CBOREncodingLevel: () => CBOREncodingLevel,
34
34
  PROTOCOL_PARAMETERS_DEFAULT: () => PROTOCOL_PARAMETERS_DEFAULT,
35
+ ScriptCache: () => ScriptCache,
35
36
  addAssets: () => addAssets,
36
37
  addressFromHexOrBech32: () => addressFromHexOrBech32,
37
38
  applyDoubleCborEncoding: () => applyDoubleCborEncoding,
@@ -66,6 +67,7 @@ __export(index_exports, {
66
67
  networkToId: () => networkToId,
67
68
  parseCMLNative: () => parseCMLNative,
68
69
  paymentCredentialOf: () => paymentCredentialOf,
70
+ scriptCborBytes: () => scriptCborBytes,
69
71
  scriptFromCMLNative: () => scriptFromCMLNative,
70
72
  scriptFromNative: () => scriptFromNative,
71
73
  scriptHashToCredential: () => scriptHashToCredential,
@@ -199,7 +201,107 @@ function networkToId(network) {
199
201
  // src/cbor.ts
200
202
  var import_core_utils = require("@lucid-evolution/core-utils");
201
203
  var import_cbor_x = require("cbor-x");
204
+
205
+ // src/script-cache.ts
206
+ var SHORT_SCRIPT_LENGTH = 1024;
207
+ var SAMPLE_COUNT = 32;
208
+ var SAMPLE_WIDTH = 16;
209
+ var TAIL_WIDTH = 512;
210
+ var MAX_CHAIN = 4;
211
+ var fingerprint = (namespace, script) => {
212
+ const length = script.length;
213
+ if (length <= SHORT_SCRIPT_LENGTH) return namespace + ":" + script;
214
+ const stride = Math.floor((length - TAIL_WIDTH) / SAMPLE_COUNT);
215
+ let key = namespace + ":" + length + ":";
216
+ for (let offset = 0; offset < SAMPLE_COUNT; offset++) {
217
+ const start = offset * stride;
218
+ key += script.slice(start, start + SAMPLE_WIDTH);
219
+ }
220
+ return key + script.slice(length - TAIL_WIDTH);
221
+ };
222
+ var ScriptCache = class {
223
+ /**
224
+ * @param capacity maximum number of entries
225
+ * @param maxWeight maximum total weight, see `weigh`
226
+ * @param weigh approximate retained bytes of an entry besides its key
227
+ */
228
+ constructor(capacity, maxWeight, weigh = () => 0) {
229
+ this.capacity = capacity;
230
+ this.maxWeight = maxWeight;
231
+ this.weigh = weigh;
232
+ }
233
+ buckets = /* @__PURE__ */ new Map();
234
+ /** Insertion order, for first-in first-out eviction. */
235
+ order = /* @__PURE__ */ new Set();
236
+ totalWeight = 0;
237
+ get size() {
238
+ return this.order.size;
239
+ }
240
+ get(namespace, script) {
241
+ const bucket = this.buckets.get(fingerprint(namespace, script));
242
+ if (bucket === void 0) return void 0;
243
+ for (const entry of bucket) {
244
+ if (entry.script === script) return entry.value;
245
+ }
246
+ return void 0;
247
+ }
248
+ set(namespace, script, value) {
249
+ const weight = script.length + this.weigh(value);
250
+ if (weight > this.maxWeight) return;
251
+ const key = fingerprint(namespace, script);
252
+ const previous = this.buckets.get(key);
253
+ if (previous !== void 0) {
254
+ const existing = previous.find((entry2) => entry2.script === script);
255
+ if (existing !== void 0) this.remove(existing);
256
+ if (previous.length >= MAX_CHAIN) this.remove(previous[0]);
257
+ }
258
+ const entry = { key, script, value, weight };
259
+ const bucket = this.buckets.get(key);
260
+ if (bucket === void 0) this.buckets.set(key, [entry]);
261
+ else bucket.push(entry);
262
+ this.order.add(entry);
263
+ this.totalWeight += weight;
264
+ while (this.order.size > this.capacity || this.totalWeight > this.maxWeight) {
265
+ this.remove(this.order.values().next().value);
266
+ }
267
+ }
268
+ clear() {
269
+ this.buckets.clear();
270
+ this.order.clear();
271
+ this.totalWeight = 0;
272
+ }
273
+ remove(entry) {
274
+ const bucket = this.buckets.get(entry.key);
275
+ if (bucket !== void 0) {
276
+ const index = bucket.indexOf(entry);
277
+ if (index !== -1) bucket.splice(index, 1);
278
+ if (bucket.length === 0) this.buckets.delete(entry.key);
279
+ }
280
+ if (this.order.delete(entry)) this.totalWeight -= entry.weight;
281
+ }
282
+ /**
283
+ * Returns the cached value, or computes, stores and returns it. A `compute`
284
+ * that throws stores nothing.
285
+ */
286
+ getOrCompute(namespace, script, compute) {
287
+ const cached = this.get(namespace, script);
288
+ if (cached !== void 0) return cached;
289
+ const value = compute();
290
+ this.set(namespace, script, value);
291
+ return value;
292
+ }
293
+ };
294
+
295
+ // src/cbor.ts
202
296
  var applyDoubleCborEncoding = (script) => {
297
+ if (typeof script !== "string") return decodingDoubleCborEncoding(script);
298
+ const cached = doubleCborCache.get("", script);
299
+ if (cached !== void 0) return cached;
300
+ const encoded = doubleCborEncoding(script);
301
+ doubleCborCache.set("", script, encoded);
302
+ return encoded;
303
+ };
304
+ var decodingDoubleCborEncoding = (script) => {
203
305
  try {
204
306
  (0, import_cbor_x.decode)((0, import_cbor_x.decode)((0, import_core_utils.fromHex)(script)));
205
307
  return script;
@@ -212,6 +314,75 @@ var applyDoubleCborEncoding = (script) => {
212
314
  }
213
315
  }
214
316
  };
317
+ var doubleCborEncoding = (script) => {
318
+ const layers = bytestringLayers(script);
319
+ switch (layers) {
320
+ case 2:
321
+ return script;
322
+ case 1:
323
+ return bytestringHeaderHex(script.length / 2) + script.toLowerCase();
324
+ case 0: {
325
+ const inner = bytestringHeaderHex(script.length / 2);
326
+ const innerLength = script.length / 2 + inner.length / 2;
327
+ return bytestringHeaderHex(innerLength) + inner + script.toLowerCase();
328
+ }
329
+ default:
330
+ return decodingDoubleCborEncoding(script);
331
+ }
332
+ };
333
+ var doubleCborCache = new ScriptCache(
334
+ 4096,
335
+ 64 * 1024 * 1024,
336
+ // Overcounts a script that is already double encoded, whose result is the
337
+ // key itself.
338
+ (encoded) => encoded.length
339
+ );
340
+ var NON_HEX = /[^0-9a-fA-F]/;
341
+ var hexByte = (hex, index) => parseInt(hex.slice(index * 2, index * 2 + 2), 16);
342
+ var itemHeader = (hex, offset, end) => {
343
+ if (offset >= end) return void 0;
344
+ const token = hexByte(hex, offset);
345
+ const major = token >> 5;
346
+ if (major > 2) return void 0;
347
+ const info = token & 31;
348
+ let argument;
349
+ let headerLength;
350
+ if (info < 24) {
351
+ argument = info;
352
+ headerLength = 1;
353
+ } else if (info <= 26) {
354
+ headerLength = 1 + (1 << info - 24);
355
+ if (offset + headerLength > end) return void 0;
356
+ argument = 0;
357
+ for (let index = offset + 1; index < offset + headerLength; index++) {
358
+ argument = argument * 256 + hexByte(hex, index);
359
+ }
360
+ } else {
361
+ return void 0;
362
+ }
363
+ const payload = major === 2 ? argument : 0;
364
+ return { major, span: headerLength + payload, headerLength };
365
+ };
366
+ var bytestringLayers = (script) => {
367
+ if (script.length === 0 || script.length % 2 !== 0) return void 0;
368
+ if (NON_HEX.test(script)) return void 0;
369
+ const length = script.length / 2;
370
+ const outer = itemHeader(script, 0, length);
371
+ if (outer === void 0) return void 0;
372
+ if (outer.span !== length) return 0;
373
+ if (outer.major !== 2) return 1;
374
+ if (outer.headerLength === length) return void 0;
375
+ const inner = itemHeader(script, outer.headerLength, length);
376
+ if (inner === void 0) return void 0;
377
+ return inner.span === length - outer.headerLength ? 2 : 1;
378
+ };
379
+ var bytestringHeaderHex = (length) => {
380
+ if (length < 24) return byteHex(64 + length);
381
+ if (length < 256) return "58" + byteHex(length);
382
+ if (length < 65536) return "59" + length.toString(16).padStart(4, "0");
383
+ return "5a" + length.toString(16).padStart(8, "0");
384
+ };
385
+ var byteHex = (byte) => byte.toString(16).padStart(2, "0");
215
386
  var applySingleCborEncoding = (script) => {
216
387
  try {
217
388
  (0, import_cbor_x.decode)((0, import_cbor_x.decode)((0, import_core_utils.fromHex)(script)));
@@ -314,77 +485,165 @@ function validatorToAddress(network, validator, stakeCredential) {
314
485
  });
315
486
  }
316
487
  function validatorToScriptHash(validator) {
317
- return (0, import_core_utils2.withCMLScope)((own) => {
318
- switch (validator.type) {
319
- case "Native":
320
- return own(
321
- own(CML.NativeScript.from_cbor_hex(validator.script)).hash()
322
- ).to_hex();
323
- case "PlutusV1": {
324
- const script = own(
325
- CML.PlutusV1Script.from_cbor_hex(
326
- applyDoubleCborEncoding(validator.script)
327
- )
328
- );
329
- return own(own(CML.PlutusScript.from_v1(script)).hash()).to_hex();
330
- }
331
- case "PlutusV2": {
332
- const script = own(
333
- CML.PlutusV2Script.from_cbor_hex(
334
- applyDoubleCborEncoding(validator.script)
335
- )
336
- );
337
- return own(own(CML.PlutusScript.from_v2(script)).hash()).to_hex();
338
- }
339
- case "PlutusV3": {
340
- const script = own(
341
- CML.PlutusV3Script.from_cbor_hex(
342
- applyDoubleCborEncoding(validator.script)
343
- )
344
- );
345
- return own(own(CML.PlutusScript.from_v3(script)).hash()).to_hex();
346
- }
347
- default:
348
- throw new Error("No variant matched");
349
- }
350
- });
488
+ const info = tryScriptInfo(validator);
489
+ return info === void 0 ? decodingValidatorToScriptHash(validator) : info.hash;
490
+ }
491
+ function scriptCborBytes(script) {
492
+ return scriptInfo(script).bytes.slice();
351
493
  }
352
494
  function toScriptRef(script) {
495
+ const info = tryScriptInfo(script);
496
+ if (info === void 0) return decodingToScriptRef(script);
497
+ const { bytes } = info;
353
498
  return (0, import_core_utils2.withCMLScope)((own) => {
354
499
  switch (script.type) {
355
500
  case "Native":
356
501
  return CML.Script.new_native(
357
- own(CML.NativeScript.from_cbor_hex(script.script))
502
+ own(CML.NativeScript.from_cbor_bytes(bytes))
358
503
  );
359
504
  case "PlutusV1":
360
505
  return CML.Script.new_plutus_v1(
361
- own(
362
- CML.PlutusV1Script.from_cbor_hex(
363
- applyDoubleCborEncoding(script.script)
364
- )
365
- )
506
+ own(CML.PlutusV1Script.from_cbor_bytes(bytes))
366
507
  );
367
508
  case "PlutusV2":
368
509
  return CML.Script.new_plutus_v2(
369
- own(
370
- CML.PlutusV2Script.from_cbor_hex(
371
- applyDoubleCborEncoding(script.script)
372
- )
373
- )
510
+ own(CML.PlutusV2Script.from_cbor_bytes(bytes))
374
511
  );
375
512
  case "PlutusV3":
376
513
  return CML.Script.new_plutus_v3(
377
- own(
378
- CML.PlutusV3Script.from_cbor_hex(
379
- applyDoubleCborEncoding(script.script)
380
- )
381
- )
514
+ own(CML.PlutusV3Script.from_cbor_bytes(bytes))
382
515
  );
383
516
  default:
384
517
  throw new Error("No variant matched.");
385
518
  }
386
519
  });
387
520
  }
521
+ var scriptInfoCache = new ScriptCache(
522
+ 4096,
523
+ 64 * 1024 * 1024,
524
+ (info) => info.bytes.length + info.hash.length
525
+ );
526
+ var scriptInfo = (script) => scriptInfoCache.getOrCompute(
527
+ script.type,
528
+ script.script,
529
+ () => computeScriptInfo(script)
530
+ );
531
+ var tryScriptInfo = (script) => {
532
+ try {
533
+ if (typeof script.script !== "string") return void 0;
534
+ return scriptInfo(script);
535
+ } catch {
536
+ return void 0;
537
+ }
538
+ };
539
+ var computeScriptInfo = ({ type, script }) => (0, import_core_utils2.withCMLScope)((own) => {
540
+ switch (type) {
541
+ case "Native": {
542
+ const bytes = (0, import_core_utils2.fromHex)(script);
543
+ const hash = own(
544
+ own(CML.NativeScript.from_cbor_bytes(bytes)).hash()
545
+ ).to_hex();
546
+ return { hash, bytes };
547
+ }
548
+ case "PlutusV1": {
549
+ const bytes = (0, import_core_utils2.fromHex)(applyDoubleCborEncoding(script));
550
+ const plutus = own(
551
+ CML.PlutusScript.from_v1(
552
+ own(CML.PlutusV1Script.from_cbor_bytes(bytes))
553
+ )
554
+ );
555
+ return { hash: own(plutus.hash()).to_hex(), bytes };
556
+ }
557
+ case "PlutusV2": {
558
+ const bytes = (0, import_core_utils2.fromHex)(applyDoubleCborEncoding(script));
559
+ const plutus = own(
560
+ CML.PlutusScript.from_v2(
561
+ own(CML.PlutusV2Script.from_cbor_bytes(bytes))
562
+ )
563
+ );
564
+ return { hash: own(plutus.hash()).to_hex(), bytes };
565
+ }
566
+ case "PlutusV3": {
567
+ const bytes = (0, import_core_utils2.fromHex)(applyDoubleCborEncoding(script));
568
+ const plutus = own(
569
+ CML.PlutusScript.from_v3(
570
+ own(CML.PlutusV3Script.from_cbor_bytes(bytes))
571
+ )
572
+ );
573
+ return { hash: own(plutus.hash()).to_hex(), bytes };
574
+ }
575
+ default:
576
+ throw new Error("No variant matched");
577
+ }
578
+ });
579
+ var decodingValidatorToScriptHash = (validator) => (0, import_core_utils2.withCMLScope)((own) => {
580
+ switch (validator.type) {
581
+ case "Native":
582
+ return own(
583
+ own(CML.NativeScript.from_cbor_hex(validator.script)).hash()
584
+ ).to_hex();
585
+ case "PlutusV1": {
586
+ const script = own(
587
+ CML.PlutusV1Script.from_cbor_hex(
588
+ applyDoubleCborEncoding(validator.script)
589
+ )
590
+ );
591
+ return own(own(CML.PlutusScript.from_v1(script)).hash()).to_hex();
592
+ }
593
+ case "PlutusV2": {
594
+ const script = own(
595
+ CML.PlutusV2Script.from_cbor_hex(
596
+ applyDoubleCborEncoding(validator.script)
597
+ )
598
+ );
599
+ return own(own(CML.PlutusScript.from_v2(script)).hash()).to_hex();
600
+ }
601
+ case "PlutusV3": {
602
+ const script = own(
603
+ CML.PlutusV3Script.from_cbor_hex(
604
+ applyDoubleCborEncoding(validator.script)
605
+ )
606
+ );
607
+ return own(own(CML.PlutusScript.from_v3(script)).hash()).to_hex();
608
+ }
609
+ default:
610
+ throw new Error("No variant matched");
611
+ }
612
+ });
613
+ var decodingToScriptRef = (script) => (0, import_core_utils2.withCMLScope)((own) => {
614
+ switch (script.type) {
615
+ case "Native":
616
+ return CML.Script.new_native(
617
+ own(CML.NativeScript.from_cbor_hex(script.script))
618
+ );
619
+ case "PlutusV1":
620
+ return CML.Script.new_plutus_v1(
621
+ own(
622
+ CML.PlutusV1Script.from_cbor_hex(
623
+ applyDoubleCborEncoding(script.script)
624
+ )
625
+ )
626
+ );
627
+ case "PlutusV2":
628
+ return CML.Script.new_plutus_v2(
629
+ own(
630
+ CML.PlutusV2Script.from_cbor_hex(
631
+ applyDoubleCborEncoding(script.script)
632
+ )
633
+ )
634
+ );
635
+ case "PlutusV3":
636
+ return CML.Script.new_plutus_v3(
637
+ own(
638
+ CML.PlutusV3Script.from_cbor_hex(
639
+ applyDoubleCborEncoding(script.script)
640
+ )
641
+ )
642
+ );
643
+ default:
644
+ throw new Error("No variant matched.");
645
+ }
646
+ });
388
647
  function fromScriptRef(scriptRef) {
389
648
  return (0, import_core_utils2.withCMLScope)((own) => {
390
649
  const kind = scriptRef.kind();
@@ -482,12 +741,24 @@ var addressDetails = (address) => ({
482
741
  bech32: address.to_bech32(void 0),
483
742
  hex: address.to_hex()
484
743
  });
485
- function getAddressDetails(address) {
744
+ var HEX_PATTERN = /^[0-9a-fA-F]*$/;
745
+ var parseShelleyAddress = (address) => {
746
+ if (HEX_PATTERN.test(address)) {
747
+ try {
748
+ return CML.Address.from_hex(address);
749
+ } catch (_e) {
750
+ }
751
+ }
486
752
  try {
487
- return (0, import_core_utils3.withCMLScope)((own) => {
488
- const parsedAddress = own(
489
- CML.BaseAddress.from_address(own(addressFromHexOrBech32(address)))
490
- );
753
+ return CML.Address.from_bech32(address);
754
+ } catch (_e) {
755
+ return void 0;
756
+ }
757
+ };
758
+ var shelleyAddressDetails = (address, own) => {
759
+ switch (address.kind()) {
760
+ case CML.AddressKind.Base: {
761
+ const parsedAddress = own(CML.BaseAddress.from_address(address));
491
762
  const paymentCredential = credentialDetails(
492
763
  own(parsedAddress.payment()),
493
764
  own
@@ -506,16 +777,9 @@ function getAddressDetails(address) {
506
777
  paymentCredential,
507
778
  stakeCredential
508
779
  };
509
- });
510
- } catch (_e) {
511
- }
512
- try {
513
- return (0, import_core_utils3.withCMLScope)((own) => {
514
- const parsedAddress = own(
515
- CML.EnterpriseAddress.from_address(
516
- own(addressFromHexOrBech32(address))
517
- )
518
- );
780
+ }
781
+ case CML.AddressKind.Enterprise: {
782
+ const parsedAddress = own(CML.EnterpriseAddress.from_address(address));
519
783
  const paymentCredential = credentialDetails(
520
784
  own(parsedAddress.payment()),
521
785
  own
@@ -529,14 +793,9 @@ function getAddressDetails(address) {
529
793
  address: details,
530
794
  paymentCredential
531
795
  };
532
- });
533
- } catch (_e) {
534
- }
535
- try {
536
- return (0, import_core_utils3.withCMLScope)((own) => {
537
- const parsedAddress = own(
538
- CML.PointerAddress.from_address(own(addressFromHexOrBech32(address)))
539
- );
796
+ }
797
+ case CML.AddressKind.Ptr: {
798
+ const parsedAddress = own(CML.PointerAddress.from_address(address));
540
799
  const paymentCredential = credentialDetails(
541
800
  own(parsedAddress.payment()),
542
801
  own
@@ -550,14 +809,9 @@ function getAddressDetails(address) {
550
809
  address: details,
551
810
  paymentCredential
552
811
  };
553
- });
554
- } catch (_e) {
555
- }
556
- try {
557
- return (0, import_core_utils3.withCMLScope)((own) => {
558
- const parsedAddress = own(
559
- CML.RewardAddress.from_address(own(addressFromHexOrBech32(address)))
560
- );
812
+ }
813
+ case CML.AddressKind.Reward: {
814
+ const parsedAddress = own(CML.RewardAddress.from_address(address));
561
815
  const stakeCredential = credentialDetails(
562
816
  own(parsedAddress.payment()),
563
817
  own
@@ -566,36 +820,83 @@ function getAddressDetails(address) {
566
820
  own(parsedAddress.to_address())
567
821
  );
568
822
  return { type: "Reward", networkId, address: details, stakeCredential };
823
+ }
824
+ default:
825
+ return void 0;
826
+ }
827
+ };
828
+ var byronAddressDetails = (address) => (0, import_core_utils3.withCMLScope)((own) => {
829
+ const parsedAddress = own(
830
+ ((address2) => {
831
+ if (HEX_PATTERN.test(address2)) {
832
+ try {
833
+ return CML.ByronAddress.from_cbor_hex(address2);
834
+ } catch (_e) {
835
+ }
836
+ }
837
+ try {
838
+ return CML.ByronAddress.from_base58(address2);
839
+ } catch (_e) {
840
+ return void 0;
841
+ }
842
+ })(address)
843
+ );
844
+ if (!parsedAddress) return void 0;
845
+ return {
846
+ type: "Byron",
847
+ networkId: own(parsedAddress.content()).network_id(),
848
+ address: {
849
+ bech32: "",
850
+ hex: own(parsedAddress.to_address()).to_hex()
851
+ }
852
+ };
853
+ });
854
+ var parseAddressDetails = (address) => {
855
+ try {
856
+ const details = (0, import_core_utils3.withCMLScope)((own) => {
857
+ const parsedAddress = own(parseShelleyAddress(address));
858
+ return parsedAddress && shelleyAddressDetails(parsedAddress, own);
569
859
  });
860
+ if (details) return details;
570
861
  } catch (_e) {
571
862
  }
572
863
  try {
573
- return (0, import_core_utils3.withCMLScope)((own) => {
574
- const parsedAddress = own(
575
- ((address2) => {
576
- try {
577
- return CML.ByronAddress.from_cbor_hex(address2);
578
- } catch (_e) {
579
- try {
580
- return CML.ByronAddress.from_base58(address2);
581
- } catch (_e2) {
582
- throw new Error("Could not deserialize address.");
583
- }
584
- }
585
- })(address)
586
- );
587
- return {
588
- type: "Byron",
589
- networkId: own(parsedAddress.content()).network_id(),
590
- address: {
591
- bech32: "",
592
- hex: own(parsedAddress.to_address()).to_hex()
593
- }
594
- };
595
- });
864
+ const details = byronAddressDetails(address);
865
+ if (details) return details;
596
866
  } catch (_e) {
597
867
  }
598
868
  throw new Error("No address type matched for: " + address);
869
+ };
870
+ var ADDRESS_DETAILS_CACHE_CAPACITY = 1e4;
871
+ var addressDetailsCache = /* @__PURE__ */ new Map();
872
+ var copyCredential = (credential) => ({
873
+ type: credential.type,
874
+ hash: credential.hash
875
+ });
876
+ var copyAddressDetails = (details) => {
877
+ const copy = {
878
+ type: details.type,
879
+ networkId: details.networkId,
880
+ address: { bech32: details.address.bech32, hex: details.address.hex }
881
+ };
882
+ if (details.paymentCredential) {
883
+ copy.paymentCredential = copyCredential(details.paymentCredential);
884
+ }
885
+ if (details.stakeCredential) {
886
+ copy.stakeCredential = copyCredential(details.stakeCredential);
887
+ }
888
+ return copy;
889
+ };
890
+ function getAddressDetails(address) {
891
+ let details = addressDetailsCache.get(address);
892
+ if (!details) {
893
+ details = parseAddressDetails(address);
894
+ if (addressDetailsCache.size >= ADDRESS_DETAILS_CACHE_CAPACITY) {
895
+ addressDetailsCache.delete(addressDetailsCache.keys().next().value);
896
+ }
897
+ addressDetailsCache.set(address, details);
898
+ }
899
+ return copyAddressDetails(details);
599
900
  }
600
901
 
601
902
  // src/cost_model.ts
@@ -1745,6 +2046,7 @@ var fromCMLRedeemerTag = (tag) => {
1745
2046
  0 && (module.exports = {
1746
2047
  CBOREncodingLevel,
1747
2048
  PROTOCOL_PARAMETERS_DEFAULT,
2049
+ ScriptCache,
1748
2050
  addAssets,
1749
2051
  addressFromHexOrBech32,
1750
2052
  applyDoubleCborEncoding,
@@ -1779,6 +2081,7 @@ var fromCMLRedeemerTag = (tag) => {
1779
2081
  networkToId,
1780
2082
  parseCMLNative,
1781
2083
  paymentCredentialOf,
2084
+ scriptCborBytes,
1782
2085
  scriptFromCMLNative,
1783
2086
  scriptFromNative,
1784
2087
  scriptHashToCredential,
package/dist/index.d.cts CHANGED
@@ -93,6 +93,12 @@ declare function networkToId(network: Network): number;
93
93
 
94
94
  declare function validatorToAddress(network: Network, validator: SpendingValidator, stakeCredential?: Credential): Address;
95
95
  declare function validatorToScriptHash(validator: Validator): ScriptHash;
96
+ /**
97
+ * The script's CBOR as CML reads it: the double CBOR encoded script
98
+ * (`applyDoubleCborEncoding`) for Plutus scripts, the script itself for native
99
+ * scripts. Returns a fresh copy.
100
+ */
101
+ declare function scriptCborBytes(script: Script): Uint8Array;
96
102
  declare function toScriptRef(script: Script): CML.Script;
97
103
  declare function fromScriptRef(scriptRef: CML.Script): Script;
98
104
  declare function mintingPolicyToId(mintingPolicy: MintingPolicy): PolicyId;
@@ -103,6 +109,49 @@ declare function mintingPolicyToId(mintingPolicy: MintingPolicy): PolicyId;
103
109
  */
104
110
  declare function applyParamsToScript<T extends unknown[] = Data[]>(plutusScript: string, params: Exact<[...T]>, type?: T): string;
105
111
 
112
+ /**
113
+ * Bounded memo tables keyed by script text.
114
+ *
115
+ * Script hex strings are long (a typical Plutus validator is 10-40k hex
116
+ * characters). V8 hashes a string longer than 16383 characters by its length
117
+ * alone, so a `Map` keyed by the script text puts every script of the same
118
+ * length in one hash bucket and a lookup can compare tens of kilobytes per
119
+ * entry. Parameterized validators make that common: every instance has the
120
+ * same length and differs only near the end. The tables here hash a short
121
+ * fingerprint of the script instead and confirm a hit by comparing the full
122
+ * text, keeping at most `MAX_CHAIN` scripts per fingerprint.
123
+ *
124
+ * Store only immutable values: strings, or byte arrays that are never handed
125
+ * to callers (return copies). Never store CML objects. Eviction is first-in
126
+ * first-out.
127
+ */
128
+ /** A bounded memo table keyed by a namespace (such as the script type) and script text. */
129
+ declare class ScriptCache<V> {
130
+ private readonly capacity;
131
+ private readonly maxWeight;
132
+ private readonly weigh;
133
+ private readonly buckets;
134
+ /** Insertion order, for first-in first-out eviction. */
135
+ private readonly order;
136
+ private totalWeight;
137
+ /**
138
+ * @param capacity maximum number of entries
139
+ * @param maxWeight maximum total weight, see `weigh`
140
+ * @param weigh approximate retained bytes of an entry besides its key
141
+ */
142
+ constructor(capacity: number, maxWeight: number, weigh?: (value: V) => number);
143
+ get size(): number;
144
+ get(namespace: string, script: string): V | undefined;
145
+ set(namespace: string, script: string, value: V): void;
146
+ clear(): void;
147
+ private remove;
148
+ /**
149
+ * Returns the cached value, or computes, stores and returns it. A `compute`
150
+ * that throws stores nothing.
151
+ */
152
+ getOrCompute(namespace: string, script: string, compute: () => V): V;
153
+ }
154
+
106
155
  /**
107
156
  * Converts unix time to slot based on the network. For "Custom" network
108
157
  * it is advisable use `unixTimeToSlot` method from `LucidEvolution`
@@ -205,4 +254,4 @@ declare const stringify: (data: any) => string;
205
254
  declare const toCMLRedeemerTag: (tag: string) => CML.RedeemerTag;
206
255
  declare const fromCMLRedeemerTag: (tag: CML.RedeemerTag) => RedeemerTag;
207
256
 
208
- export { CBOREncodingLevel, type CMLNative, PROTOCOL_PARAMETERS_DEFAULT, type SortOrder, addAssets, addressFromHexOrBech32, applyDoubleCborEncoding, applyParamsToScript, applySingleCborEncoding, assetsToValue, calculateMinLovelaceFromUTxO, coreToOutRef, coreToTxOutput, coreToUtxo, coresToOutRefs, coresToTxOutputs, coresToUtxos, createCostModels, credentialToAddress, credentialToRewardAddress, datumJsonToCbor, datumToHash, drepIDToCredential, fromCMLRedeemerTag, fromLabel, fromScriptRef, fromUnit, generatePrivateKey, generateSeedPhrase, getAddressDetails, getInputIndices, getUniqueTokenName, isEqualUTxO, keyHashToCredential, mintingPolicyToId, networkToId, parseCMLNative, paymentCredentialOf, scriptFromCMLNative, scriptFromNative, scriptHashToCredential, selectUTxOs, slotToUnixTime, sortCanonical, sortUTxOs, stakeCredentialOf, stringify, toCMLNativeScript, toCMLRedeemerTag, toLabel, toPublicKey, toScriptRef, toUnit, unixTimeToSlot, utxoToCore, utxoToTransactionInput, utxoToTransactionOutput, utxosToCores, validatorToAddress, validatorToRewardAddress, validatorToScriptHash, valueToAssets };
257
+ export { CBOREncodingLevel, type CMLNative, PROTOCOL_PARAMETERS_DEFAULT, ScriptCache, type SortOrder, addAssets, addressFromHexOrBech32, applyDoubleCborEncoding, applyParamsToScript, applySingleCborEncoding, assetsToValue, calculateMinLovelaceFromUTxO, coreToOutRef, coreToTxOutput, coreToUtxo, coresToOutRefs, coresToTxOutputs, coresToUtxos, createCostModels, credentialToAddress, credentialToRewardAddress, datumJsonToCbor, datumToHash, drepIDToCredential, fromCMLRedeemerTag, fromLabel, fromScriptRef, fromUnit, generatePrivateKey, generateSeedPhrase, getAddressDetails, getInputIndices, getUniqueTokenName, isEqualUTxO, keyHashToCredential, mintingPolicyToId, networkToId, parseCMLNative, paymentCredentialOf, scriptCborBytes, scriptFromCMLNative, scriptFromNative, scriptHashToCredential, selectUTxOs, slotToUnixTime, sortCanonical, sortUTxOs, stakeCredentialOf, stringify, toCMLNativeScript, toCMLRedeemerTag, toLabel, toPublicKey, toScriptRef, toUnit, unixTimeToSlot, utxoToCore, utxoToTransactionInput, utxoToTransactionOutput, utxosToCores, validatorToAddress, validatorToRewardAddress, validatorToScriptHash, valueToAssets };
package/dist/index.d.ts CHANGED
@@ -93,6 +93,12 @@ declare function networkToId(network: Network): number;
93
93
 
94
94
  declare function validatorToAddress(network: Network, validator: SpendingValidator, stakeCredential?: Credential): Address;
95
95
  declare function validatorToScriptHash(validator: Validator): ScriptHash;
96
+ /**
97
+ * The script's CBOR as CML reads it: the double CBOR encoded script
98
+ * (`applyDoubleCborEncoding`) for Plutus scripts, the script itself for native
99
+ * scripts. Returns a fresh copy.
100
+ */
101
+ declare function scriptCborBytes(script: Script): Uint8Array;
96
102
  declare function toScriptRef(script: Script): CML.Script;
97
103
  declare function fromScriptRef(scriptRef: CML.Script): Script;
98
104
  declare function mintingPolicyToId(mintingPolicy: MintingPolicy): PolicyId;
@@ -103,6 +109,49 @@ declare function mintingPolicyToId(mintingPolicy: MintingPolicy): PolicyId;
103
109
  */
104
110
  declare function applyParamsToScript<T extends unknown[] = Data[]>(plutusScript: string, params: Exact<[...T]>, type?: T): string;
105
111
 
112
+ /**
113
+ * Bounded memo tables keyed by script text.
114
+ *
115
+ * Script hex strings are long (a typical Plutus validator is 10-40k hex
116
+ * characters). V8 hashes a string longer than 16383 characters by its length
117
+ * alone, so a `Map` keyed by the script text puts every script of the same
118
+ * length in one hash bucket and a lookup can compare tens of kilobytes per
119
+ * entry. Parameterized validators make that common: every instance has the
120
+ * same length and differs only near the end. The tables here hash a short
121
+ * fingerprint of the script instead and confirm a hit by comparing the full
122
+ * text, keeping at most `MAX_CHAIN` scripts per fingerprint.
123
+ *
124
+ * Store only immutable values: strings, or byte arrays that are never handed
125
+ * to callers (return copies). Never store CML objects. Eviction is first-in
126
+ * first-out.
127
+ */
128
+ /** A bounded memo table keyed by a namespace (such as the script type) and script text. */
129
+ declare class ScriptCache<V> {
130
+ private readonly capacity;
131
+ private readonly maxWeight;
132
+ private readonly weigh;
133
+ private readonly buckets;
134
+ /** Insertion order, for first-in first-out eviction. */
135
+ private readonly order;
136
+ private totalWeight;
137
+ /**
138
+ * @param capacity maximum number of entries
139
+ * @param maxWeight maximum total weight, see `weigh`
140
+ * @param weigh approximate retained bytes of an entry besides its key
141
+ */
142
+ constructor(capacity: number, maxWeight: number, weigh?: (value: V) => number);
143
+ get size(): number;
144
+ get(namespace: string, script: string): V | undefined;
145
+ set(namespace: string, script: string, value: V): void;
146
+ clear(): void;
147
+ private remove;
148
+ /**
149
+ * Returns the cached value, or computes, stores and returns it. A `compute`
150
+ * that throws stores nothing.
151
+ */
152
+ getOrCompute(namespace: string, script: string, compute: () => V): V;
153
+ }
154
+
106
155
  /**
107
156
  * Converts unix time to slot based on the network. For "Custom" network
108
157
  * it is advisable use `unixTimeToSlot` method from `LucidEvolution`
@@ -205,4 +254,4 @@ declare const stringify: (data: any) => string;
205
254
  declare const toCMLRedeemerTag: (tag: string) => CML.RedeemerTag;
206
255
  declare const fromCMLRedeemerTag: (tag: CML.RedeemerTag) => RedeemerTag;
207
256
 
208
- export { CBOREncodingLevel, type CMLNative, PROTOCOL_PARAMETERS_DEFAULT, type SortOrder, addAssets, addressFromHexOrBech32, applyDoubleCborEncoding, applyParamsToScript, applySingleCborEncoding, assetsToValue, calculateMinLovelaceFromUTxO, coreToOutRef, coreToTxOutput, coreToUtxo, coresToOutRefs, coresToTxOutputs, coresToUtxos, createCostModels, credentialToAddress, credentialToRewardAddress, datumJsonToCbor, datumToHash, drepIDToCredential, fromCMLRedeemerTag, fromLabel, fromScriptRef, fromUnit, generatePrivateKey, generateSeedPhrase, getAddressDetails, getInputIndices, getUniqueTokenName, isEqualUTxO, keyHashToCredential, mintingPolicyToId, networkToId, parseCMLNative, paymentCredentialOf, scriptFromCMLNative, scriptFromNative, scriptHashToCredential, selectUTxOs, slotToUnixTime, sortCanonical, sortUTxOs, stakeCredentialOf, stringify, toCMLNativeScript, toCMLRedeemerTag, toLabel, toPublicKey, toScriptRef, toUnit, unixTimeToSlot, utxoToCore, utxoToTransactionInput, utxoToTransactionOutput, utxosToCores, validatorToAddress, validatorToRewardAddress, validatorToScriptHash, valueToAssets };
257
+ export { CBOREncodingLevel, type CMLNative, PROTOCOL_PARAMETERS_DEFAULT, ScriptCache, type SortOrder, addAssets, addressFromHexOrBech32, applyDoubleCborEncoding, applyParamsToScript, applySingleCborEncoding, assetsToValue, calculateMinLovelaceFromUTxO, coreToOutRef, coreToTxOutput, coreToUtxo, coresToOutRefs, coresToTxOutputs, coresToUtxos, createCostModels, credentialToAddress, credentialToRewardAddress, datumJsonToCbor, datumToHash, drepIDToCredential, fromCMLRedeemerTag, fromLabel, fromScriptRef, fromUnit, generatePrivateKey, generateSeedPhrase, getAddressDetails, getInputIndices, getUniqueTokenName, isEqualUTxO, keyHashToCredential, mintingPolicyToId, networkToId, parseCMLNative, paymentCredentialOf, scriptCborBytes, scriptFromCMLNative, scriptFromNative, scriptHashToCredential, selectUTxOs, slotToUnixTime, sortCanonical, sortUTxOs, stakeCredentialOf, stringify, toCMLNativeScript, toCMLRedeemerTag, toLabel, toPublicKey, toScriptRef, toUnit, unixTimeToSlot, utxoToCore, utxoToTransactionInput, utxoToTransactionOutput, utxosToCores, validatorToAddress, validatorToRewardAddress, validatorToScriptHash, valueToAssets };
package/dist/index.js CHANGED
@@ -104,7 +104,107 @@ function networkToId(network) {
104
104
  // src/cbor.ts
105
105
  import { fromHex, toHex } from "@lucid-evolution/core-utils";
106
106
  import { decode, encode } from "cbor-x";
107
+
108
+ // src/script-cache.ts
109
+ var SHORT_SCRIPT_LENGTH = 1024;
110
+ var SAMPLE_COUNT = 32;
111
+ var SAMPLE_WIDTH = 16;
112
+ var TAIL_WIDTH = 512;
113
+ var MAX_CHAIN = 4;
114
+ var fingerprint = (namespace, script) => {
115
+ const length = script.length;
116
+ if (length <= SHORT_SCRIPT_LENGTH) return namespace + ":" + script;
117
+ const stride = Math.floor((length - TAIL_WIDTH) / SAMPLE_COUNT);
118
+ let key = namespace + ":" + length + ":";
119
+ for (let offset = 0; offset < SAMPLE_COUNT; offset++) {
120
+ const start = offset * stride;
121
+ key += script.slice(start, start + SAMPLE_WIDTH);
122
+ }
123
+ return key + script.slice(length - TAIL_WIDTH);
124
+ };
125
+ var ScriptCache = class {
126
+ /**
127
+ * @param capacity maximum number of entries
128
+ * @param maxWeight maximum total weight, see `weigh`
129
+ * @param weigh approximate retained bytes of an entry besides its key
130
+ */
131
+ constructor(capacity, maxWeight, weigh = () => 0) {
132
+ this.capacity = capacity;
133
+ this.maxWeight = maxWeight;
134
+ this.weigh = weigh;
135
+ }
136
+ buckets = /* @__PURE__ */ new Map();
137
+ /** Insertion order, for first-in first-out eviction. */
138
+ order = /* @__PURE__ */ new Set();
139
+ totalWeight = 0;
140
+ get size() {
141
+ return this.order.size;
142
+ }
143
+ get(namespace, script) {
144
+ const bucket = this.buckets.get(fingerprint(namespace, script));
145
+ if (bucket === void 0) return void 0;
146
+ for (const entry of bucket) {
147
+ if (entry.script === script) return entry.value;
148
+ }
149
+ return void 0;
150
+ }
151
+ set(namespace, script, value) {
152
+ const weight = script.length + this.weigh(value);
153
+ if (weight > this.maxWeight) return;
154
+ const key = fingerprint(namespace, script);
155
+ const previous = this.buckets.get(key);
156
+ if (previous !== void 0) {
157
+ const existing = previous.find((entry2) => entry2.script === script);
158
+ if (existing !== void 0) this.remove(existing);
159
+ if (previous.length >= MAX_CHAIN) this.remove(previous[0]);
160
+ }
161
+ const entry = { key, script, value, weight };
162
+ const bucket = this.buckets.get(key);
163
+ if (bucket === void 0) this.buckets.set(key, [entry]);
164
+ else bucket.push(entry);
165
+ this.order.add(entry);
166
+ this.totalWeight += weight;
167
+ while (this.order.size > this.capacity || this.totalWeight > this.maxWeight) {
168
+ this.remove(this.order.values().next().value);
169
+ }
170
+ }
171
+ clear() {
172
+ this.buckets.clear();
173
+ this.order.clear();
174
+ this.totalWeight = 0;
175
+ }
176
+ remove(entry) {
177
+ const bucket = this.buckets.get(entry.key);
178
+ if (bucket !== void 0) {
179
+ const index = bucket.indexOf(entry);
180
+ if (index !== -1) bucket.splice(index, 1);
181
+ if (bucket.length === 0) this.buckets.delete(entry.key);
182
+ }
183
+ if (this.order.delete(entry)) this.totalWeight -= entry.weight;
184
+ }
185
+ /**
186
+ * Returns the cached value, or computes, stores and returns it. A `compute`
187
+ * that throws stores nothing.
188
+ */
189
+ getOrCompute(namespace, script, compute) {
190
+ const cached = this.get(namespace, script);
191
+ if (cached !== void 0) return cached;
192
+ const value = compute();
193
+ this.set(namespace, script, value);
194
+ return value;
195
+ }
196
+ };
197
+
198
+ // src/cbor.ts
107
199
  var applyDoubleCborEncoding = (script) => {
200
+ if (typeof script !== "string") return decodingDoubleCborEncoding(script);
201
+ const cached = doubleCborCache.get("", script);
202
+ if (cached !== void 0) return cached;
203
+ const encoded = doubleCborEncoding(script);
204
+ doubleCborCache.set("", script, encoded);
205
+ return encoded;
206
+ };
207
+ var decodingDoubleCborEncoding = (script) => {
108
208
  try {
109
209
  decode(decode(fromHex(script)));
110
210
  return script;
@@ -117,6 +217,75 @@ var applyDoubleCborEncoding = (script) => {
117
217
  }
118
218
  }
119
219
  };
220
+ var doubleCborEncoding = (script) => {
221
+ const layers = bytestringLayers(script);
222
+ switch (layers) {
223
+ case 2:
224
+ return script;
225
+ case 1:
226
+ return bytestringHeaderHex(script.length / 2) + script.toLowerCase();
227
+ case 0: {
228
+ const inner = bytestringHeaderHex(script.length / 2);
229
+ const innerLength = script.length / 2 + inner.length / 2;
230
+ return bytestringHeaderHex(innerLength) + inner + script.toLowerCase();
231
+ }
232
+ default:
233
+ return decodingDoubleCborEncoding(script);
234
+ }
235
+ };
236
+ var doubleCborCache = new ScriptCache(
237
+ 4096,
238
+ 64 * 1024 * 1024,
239
+ // Overcounts a script that is already double encoded, whose result is the
240
+ // key itself.
241
+ (encoded) => encoded.length
242
+ );
243
+ var NON_HEX = /[^0-9a-fA-F]/;
244
+ var hexByte = (hex, index) => parseInt(hex.slice(index * 2, index * 2 + 2), 16);
245
+ var itemHeader = (hex, offset, end) => {
246
+ if (offset >= end) return void 0;
247
+ const token = hexByte(hex, offset);
248
+ const major = token >> 5;
249
+ if (major > 2) return void 0;
250
+ const info = token & 31;
251
+ let argument;
252
+ let headerLength;
253
+ if (info < 24) {
254
+ argument = info;
255
+ headerLength = 1;
256
+ } else if (info <= 26) {
257
+ headerLength = 1 + (1 << info - 24);
258
+ if (offset + headerLength > end) return void 0;
259
+ argument = 0;
260
+ for (let index = offset + 1; index < offset + headerLength; index++) {
261
+ argument = argument * 256 + hexByte(hex, index);
262
+ }
263
+ } else {
264
+ return void 0;
265
+ }
266
+ const payload = major === 2 ? argument : 0;
267
+ return { major, span: headerLength + payload, headerLength };
268
+ };
269
+ var bytestringLayers = (script) => {
270
+ if (script.length === 0 || script.length % 2 !== 0) return void 0;
271
+ if (NON_HEX.test(script)) return void 0;
272
+ const length = script.length / 2;
273
+ const outer = itemHeader(script, 0, length);
274
+ if (outer === void 0) return void 0;
275
+ if (outer.span !== length) return 0;
276
+ if (outer.major !== 2) return 1;
277
+ if (outer.headerLength === length) return void 0;
278
+ const inner = itemHeader(script, outer.headerLength, length);
279
+ if (inner === void 0) return void 0;
280
+ return inner.span === length - outer.headerLength ? 2 : 1;
281
+ };
282
+ var bytestringHeaderHex = (length) => {
283
+ if (length < 24) return byteHex(64 + length);
284
+ if (length < 256) return "58" + byteHex(length);
285
+ if (length < 65536) return "59" + length.toString(16).padStart(4, "0");
286
+ return "5a" + length.toString(16).padStart(8, "0");
287
+ };
288
+ var byteHex = (byte) => byte.toString(16).padStart(2, "0");
120
289
  var applySingleCborEncoding = (script) => {
121
290
  try {
122
291
  decode(decode(fromHex(script)));
@@ -225,77 +394,165 @@ function validatorToAddress(network, validator, stakeCredential) {
225
394
  });
226
395
  }
227
396
  function validatorToScriptHash(validator) {
228
- return withCMLScope((own) => {
229
- switch (validator.type) {
230
- case "Native":
231
- return own(
232
- own(CML.NativeScript.from_cbor_hex(validator.script)).hash()
233
- ).to_hex();
234
- case "PlutusV1": {
235
- const script = own(
236
- CML.PlutusV1Script.from_cbor_hex(
237
- applyDoubleCborEncoding(validator.script)
238
- )
239
- );
240
- return own(own(CML.PlutusScript.from_v1(script)).hash()).to_hex();
241
- }
242
- case "PlutusV2": {
243
- const script = own(
244
- CML.PlutusV2Script.from_cbor_hex(
245
- applyDoubleCborEncoding(validator.script)
246
- )
247
- );
248
- return own(own(CML.PlutusScript.from_v2(script)).hash()).to_hex();
249
- }
250
- case "PlutusV3": {
251
- const script = own(
252
- CML.PlutusV3Script.from_cbor_hex(
253
- applyDoubleCborEncoding(validator.script)
254
- )
255
- );
256
- return own(own(CML.PlutusScript.from_v3(script)).hash()).to_hex();
257
- }
258
- default:
259
- throw new Error("No variant matched");
260
- }
261
- });
397
+ const info = tryScriptInfo(validator);
398
+ return info === void 0 ? decodingValidatorToScriptHash(validator) : info.hash;
399
+ }
400
+ function scriptCborBytes(script) {
401
+ return scriptInfo(script).bytes.slice();
262
402
  }
263
403
  function toScriptRef(script) {
404
+ const info = tryScriptInfo(script);
405
+ if (info === void 0) return decodingToScriptRef(script);
406
+ const { bytes } = info;
264
407
  return withCMLScope((own) => {
265
408
  switch (script.type) {
266
409
  case "Native":
267
410
  return CML.Script.new_native(
268
- own(CML.NativeScript.from_cbor_hex(script.script))
411
+ own(CML.NativeScript.from_cbor_bytes(bytes))
269
412
  );
270
413
  case "PlutusV1":
271
414
  return CML.Script.new_plutus_v1(
272
- own(
273
- CML.PlutusV1Script.from_cbor_hex(
274
- applyDoubleCborEncoding(script.script)
275
- )
276
- )
415
+ own(CML.PlutusV1Script.from_cbor_bytes(bytes))
277
416
  );
278
417
  case "PlutusV2":
279
418
  return CML.Script.new_plutus_v2(
280
- own(
281
- CML.PlutusV2Script.from_cbor_hex(
282
- applyDoubleCborEncoding(script.script)
283
- )
284
- )
419
+ own(CML.PlutusV2Script.from_cbor_bytes(bytes))
285
420
  );
286
421
  case "PlutusV3":
287
422
  return CML.Script.new_plutus_v3(
288
- own(
289
- CML.PlutusV3Script.from_cbor_hex(
290
- applyDoubleCborEncoding(script.script)
291
- )
292
- )
423
+ own(CML.PlutusV3Script.from_cbor_bytes(bytes))
293
424
  );
294
425
  default:
295
426
  throw new Error("No variant matched.");
296
427
  }
297
428
  });
298
429
  }
430
+ var scriptInfoCache = new ScriptCache(
431
+ 4096,
432
+ 64 * 1024 * 1024,
433
+ (info) => info.bytes.length + info.hash.length
434
+ );
435
+ var scriptInfo = (script) => scriptInfoCache.getOrCompute(
436
+ script.type,
437
+ script.script,
438
+ () => computeScriptInfo(script)
439
+ );
440
+ var tryScriptInfo = (script) => {
441
+ try {
442
+ if (typeof script.script !== "string") return void 0;
443
+ return scriptInfo(script);
444
+ } catch {
445
+ return void 0;
446
+ }
447
+ };
448
+ var computeScriptInfo = ({ type, script }) => withCMLScope((own) => {
449
+ switch (type) {
450
+ case "Native": {
451
+ const bytes = fromHex2(script);
452
+ const hash = own(
453
+ own(CML.NativeScript.from_cbor_bytes(bytes)).hash()
454
+ ).to_hex();
455
+ return { hash, bytes };
456
+ }
457
+ case "PlutusV1": {
458
+ const bytes = fromHex2(applyDoubleCborEncoding(script));
459
+ const plutus = own(
460
+ CML.PlutusScript.from_v1(
461
+ own(CML.PlutusV1Script.from_cbor_bytes(bytes))
462
+ )
463
+ );
464
+ return { hash: own(plutus.hash()).to_hex(), bytes };
465
+ }
466
+ case "PlutusV2": {
467
+ const bytes = fromHex2(applyDoubleCborEncoding(script));
468
+ const plutus = own(
469
+ CML.PlutusScript.from_v2(
470
+ own(CML.PlutusV2Script.from_cbor_bytes(bytes))
471
+ )
472
+ );
473
+ return { hash: own(plutus.hash()).to_hex(), bytes };
474
+ }
475
+ case "PlutusV3": {
476
+ const bytes = fromHex2(applyDoubleCborEncoding(script));
477
+ const plutus = own(
478
+ CML.PlutusScript.from_v3(
479
+ own(CML.PlutusV3Script.from_cbor_bytes(bytes))
480
+ )
481
+ );
482
+ return { hash: own(plutus.hash()).to_hex(), bytes };
483
+ }
484
+ default:
485
+ throw new Error("No variant matched");
486
+ }
487
+ });
488
+ var decodingValidatorToScriptHash = (validator) => withCMLScope((own) => {
489
+ switch (validator.type) {
490
+ case "Native":
491
+ return own(
492
+ own(CML.NativeScript.from_cbor_hex(validator.script)).hash()
493
+ ).to_hex();
494
+ case "PlutusV1": {
495
+ const script = own(
496
+ CML.PlutusV1Script.from_cbor_hex(
497
+ applyDoubleCborEncoding(validator.script)
498
+ )
499
+ );
500
+ return own(own(CML.PlutusScript.from_v1(script)).hash()).to_hex();
501
+ }
502
+ case "PlutusV2": {
503
+ const script = own(
504
+ CML.PlutusV2Script.from_cbor_hex(
505
+ applyDoubleCborEncoding(validator.script)
506
+ )
507
+ );
508
+ return own(own(CML.PlutusScript.from_v2(script)).hash()).to_hex();
509
+ }
510
+ case "PlutusV3": {
511
+ const script = own(
512
+ CML.PlutusV3Script.from_cbor_hex(
513
+ applyDoubleCborEncoding(validator.script)
514
+ )
515
+ );
516
+ return own(own(CML.PlutusScript.from_v3(script)).hash()).to_hex();
517
+ }
518
+ default:
519
+ throw new Error("No variant matched");
520
+ }
521
+ });
522
+ var decodingToScriptRef = (script) => withCMLScope((own) => {
523
+ switch (script.type) {
524
+ case "Native":
525
+ return CML.Script.new_native(
526
+ own(CML.NativeScript.from_cbor_hex(script.script))
527
+ );
528
+ case "PlutusV1":
529
+ return CML.Script.new_plutus_v1(
530
+ own(
531
+ CML.PlutusV1Script.from_cbor_hex(
532
+ applyDoubleCborEncoding(script.script)
533
+ )
534
+ )
535
+ );
536
+ case "PlutusV2":
537
+ return CML.Script.new_plutus_v2(
538
+ own(
539
+ CML.PlutusV2Script.from_cbor_hex(
540
+ applyDoubleCborEncoding(script.script)
541
+ )
542
+ )
543
+ );
544
+ case "PlutusV3":
545
+ return CML.Script.new_plutus_v3(
546
+ own(
547
+ CML.PlutusV3Script.from_cbor_hex(
548
+ applyDoubleCborEncoding(script.script)
549
+ )
550
+ )
551
+ );
552
+ default:
553
+ throw new Error("No variant matched.");
554
+ }
555
+ });
299
556
  function fromScriptRef(scriptRef) {
300
557
  return withCMLScope((own) => {
301
558
  const kind = scriptRef.kind();
@@ -393,12 +650,24 @@ var addressDetails = (address) => ({
393
650
  bech32: address.to_bech32(void 0),
394
651
  hex: address.to_hex()
395
652
  });
396
- function getAddressDetails(address) {
653
+ var HEX_PATTERN = /^[0-9a-fA-F]*$/;
654
+ var parseShelleyAddress = (address) => {
655
+ if (HEX_PATTERN.test(address)) {
656
+ try {
657
+ return CML.Address.from_hex(address);
658
+ } catch (_e) {
659
+ }
660
+ }
397
661
  try {
398
- return withCMLScope2((own) => {
399
- const parsedAddress = own(
400
- CML.BaseAddress.from_address(own(addressFromHexOrBech32(address)))
401
- );
662
+ return CML.Address.from_bech32(address);
663
+ } catch (_e) {
664
+ return void 0;
665
+ }
666
+ };
667
+ var shelleyAddressDetails = (address, own) => {
668
+ switch (address.kind()) {
669
+ case CML.AddressKind.Base: {
670
+ const parsedAddress = own(CML.BaseAddress.from_address(address));
402
671
  const paymentCredential = credentialDetails(
403
672
  own(parsedAddress.payment()),
404
673
  own
@@ -417,16 +686,9 @@ function getAddressDetails(address) {
417
686
  paymentCredential,
418
687
  stakeCredential
419
688
  };
420
- });
421
- } catch (_e) {
422
- }
423
- try {
424
- return withCMLScope2((own) => {
425
- const parsedAddress = own(
426
- CML.EnterpriseAddress.from_address(
427
- own(addressFromHexOrBech32(address))
428
- )
429
- );
689
+ }
690
+ case CML.AddressKind.Enterprise: {
691
+ const parsedAddress = own(CML.EnterpriseAddress.from_address(address));
430
692
  const paymentCredential = credentialDetails(
431
693
  own(parsedAddress.payment()),
432
694
  own
@@ -440,14 +702,9 @@ function getAddressDetails(address) {
440
702
  address: details,
441
703
  paymentCredential
442
704
  };
443
- });
444
- } catch (_e) {
445
- }
446
- try {
447
- return withCMLScope2((own) => {
448
- const parsedAddress = own(
449
- CML.PointerAddress.from_address(own(addressFromHexOrBech32(address)))
450
- );
705
+ }
706
+ case CML.AddressKind.Ptr: {
707
+ const parsedAddress = own(CML.PointerAddress.from_address(address));
451
708
  const paymentCredential = credentialDetails(
452
709
  own(parsedAddress.payment()),
453
710
  own
@@ -461,14 +718,9 @@ function getAddressDetails(address) {
461
718
  address: details,
462
719
  paymentCredential
463
720
  };
464
- });
465
- } catch (_e) {
466
- }
467
- try {
468
- return withCMLScope2((own) => {
469
- const parsedAddress = own(
470
- CML.RewardAddress.from_address(own(addressFromHexOrBech32(address)))
471
- );
721
+ }
722
+ case CML.AddressKind.Reward: {
723
+ const parsedAddress = own(CML.RewardAddress.from_address(address));
472
724
  const stakeCredential = credentialDetails(
473
725
  own(parsedAddress.payment()),
474
726
  own
@@ -477,36 +729,83 @@ function getAddressDetails(address) {
477
729
  own(parsedAddress.to_address())
478
730
  );
479
731
  return { type: "Reward", networkId, address: details, stakeCredential };
732
+ }
733
+ default:
734
+ return void 0;
735
+ }
736
+ };
737
+ var byronAddressDetails = (address) => withCMLScope2((own) => {
738
+ const parsedAddress = own(
739
+ ((address2) => {
740
+ if (HEX_PATTERN.test(address2)) {
741
+ try {
742
+ return CML.ByronAddress.from_cbor_hex(address2);
743
+ } catch (_e) {
744
+ }
745
+ }
746
+ try {
747
+ return CML.ByronAddress.from_base58(address2);
748
+ } catch (_e) {
749
+ return void 0;
750
+ }
751
+ })(address)
752
+ );
753
+ if (!parsedAddress) return void 0;
754
+ return {
755
+ type: "Byron",
756
+ networkId: own(parsedAddress.content()).network_id(),
757
+ address: {
758
+ bech32: "",
759
+ hex: own(parsedAddress.to_address()).to_hex()
760
+ }
761
+ };
762
+ });
763
+ var parseAddressDetails = (address) => {
764
+ try {
765
+ const details = withCMLScope2((own) => {
766
+ const parsedAddress = own(parseShelleyAddress(address));
767
+ return parsedAddress && shelleyAddressDetails(parsedAddress, own);
480
768
  });
769
+ if (details) return details;
481
770
  } catch (_e) {
482
771
  }
483
772
  try {
484
- return withCMLScope2((own) => {
485
- const parsedAddress = own(
486
- ((address2) => {
487
- try {
488
- return CML.ByronAddress.from_cbor_hex(address2);
489
- } catch (_e) {
490
- try {
491
- return CML.ByronAddress.from_base58(address2);
492
- } catch (_e2) {
493
- throw new Error("Could not deserialize address.");
494
- }
495
- }
496
- })(address)
497
- );
498
- return {
499
- type: "Byron",
500
- networkId: own(parsedAddress.content()).network_id(),
501
- address: {
502
- bech32: "",
503
- hex: own(parsedAddress.to_address()).to_hex()
504
- }
505
- };
506
- });
773
+ const details = byronAddressDetails(address);
774
+ if (details) return details;
507
775
  } catch (_e) {
508
776
  }
509
777
  throw new Error("No address type matched for: " + address);
778
+ };
779
+ var ADDRESS_DETAILS_CACHE_CAPACITY = 1e4;
780
+ var addressDetailsCache = /* @__PURE__ */ new Map();
781
+ var copyCredential = (credential) => ({
782
+ type: credential.type,
783
+ hash: credential.hash
784
+ });
785
+ var copyAddressDetails = (details) => {
786
+ const copy = {
787
+ type: details.type,
788
+ networkId: details.networkId,
789
+ address: { bech32: details.address.bech32, hex: details.address.hex }
790
+ };
791
+ if (details.paymentCredential) {
792
+ copy.paymentCredential = copyCredential(details.paymentCredential);
793
+ }
794
+ if (details.stakeCredential) {
795
+ copy.stakeCredential = copyCredential(details.stakeCredential);
796
+ }
797
+ return copy;
798
+ };
799
+ function getAddressDetails(address) {
800
+ let details = addressDetailsCache.get(address);
801
+ if (!details) {
802
+ details = parseAddressDetails(address);
803
+ if (addressDetailsCache.size >= ADDRESS_DETAILS_CACHE_CAPACITY) {
804
+ addressDetailsCache.delete(addressDetailsCache.keys().next().value);
805
+ }
806
+ addressDetailsCache.set(address, details);
807
+ }
808
+ return copyAddressDetails(details);
510
809
  }
511
810
 
512
811
  // src/cost_model.ts
@@ -1663,6 +1962,7 @@ var fromCMLRedeemerTag = (tag) => {
1663
1962
  export {
1664
1963
  CBOREncodingLevel,
1665
1964
  PROTOCOL_PARAMETERS_DEFAULT,
1965
+ ScriptCache,
1666
1966
  addAssets,
1667
1967
  addressFromHexOrBech32,
1668
1968
  applyDoubleCborEncoding,
@@ -1697,6 +1997,7 @@ export {
1697
1997
  networkToId,
1698
1998
  parseCMLNative,
1699
1999
  paymentCredentialOf,
2000
+ scriptCborBytes,
1700
2001
  scriptFromCMLNative,
1701
2002
  scriptFromNative,
1702
2003
  scriptHashToCredential,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucid-evolution/utils",
3
- "version": "0.1.75",
3
+ "version": "0.1.76",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -35,11 +35,11 @@
35
35
  "bip39": "^3.1.0",
36
36
  "cbor-x": "^1.6.0",
37
37
  "effect": "^3.10.4",
38
- "@lucid-evolution/core-types": "0.3.0",
38
+ "@lucid-evolution/core-types": "0.4.0",
39
39
  "@lucid-evolution/core-utils": "0.1.17",
40
40
  "@lucid-evolution/crc8": "0.1.8",
41
- "@lucid-evolution/plutus": "0.1.36",
42
- "@lucid-evolution/uplc": "0.2.24"
41
+ "@lucid-evolution/plutus": "0.1.37",
42
+ "@lucid-evolution/uplc": "0.3.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/node": "^20.12.8",