@d9-network/ink 0.0.6 → 0.0.8

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
@@ -466,6 +466,27 @@ function buildAllEventDecoders(metadata) {
466
466
  function getEventSignature(eventLabel) {
467
467
  return (0, _noble_hashes_blake2_js.blake2b)(new TextEncoder().encode(eventLabel), { dkLen: 32 });
468
468
  }
469
+ /**
470
+ * Create ASCII-encoded event topic (D9 chain format)
471
+ *
472
+ * D9 chain uses a format where:
473
+ * - First byte is 0x00 (null)
474
+ * - Remaining 31 bytes are ASCII characters of `ContractName::EventLabel`
475
+ * - Total is exactly 32 bytes (truncated/padded as needed)
476
+ *
477
+ * @param contractName - Contract name (e.g., "MarketMaker", "Usdt")
478
+ * @param eventLabel - Event label (e.g., "Transfer", "USDTToD9Conversion")
479
+ * @returns 32-byte topic with null prefix and ASCII-encoded path
480
+ */
481
+ function createAsciiEventTopic(contractName, eventLabel) {
482
+ const topic = new Uint8Array(32);
483
+ topic[0] = 0;
484
+ const encoder = new TextEncoder();
485
+ const fullPath = `${contractName}::${eventLabel}`;
486
+ const encoded = encoder.encode(fullPath);
487
+ topic.set(encoded.slice(0, 31), 1);
488
+ return topic;
489
+ }
469
490
 
470
491
  //#endregion
471
492
  //#region src/events.ts
@@ -517,9 +538,13 @@ var ContractEventParser = class {
517
538
  if (topics.length === 0) return null;
518
539
  const signature = topics[0];
519
540
  let eventLabel = null;
520
- for (const [label, sig] of this.eventSignatures) if (this.bytesEqual(signature, sig)) {
521
- eventLabel = label;
522
- break;
541
+ eventLabel = this.extractEventLabelFromAsciiTopic(signature);
542
+ if (eventLabel && !this.eventDecoders.has(eventLabel)) eventLabel = null;
543
+ if (!eventLabel) {
544
+ for (const [label, sig] of this.eventSignatures) if (this.bytesEqual(signature, sig)) {
545
+ eventLabel = label;
546
+ break;
547
+ }
523
548
  }
524
549
  if (!eventLabel) {
525
550
  console.warn("Unknown event signature:", signature);
@@ -531,7 +556,7 @@ var ContractEventParser = class {
531
556
  return null;
532
557
  }
533
558
  try {
534
- const decodedData = decoder(data);
559
+ const decodedData = decoder(data.slice(1));
535
560
  return {
536
561
  type: eventLabel,
537
562
  value: decodedData,
@@ -550,6 +575,25 @@ var ContractEventParser = class {
550
575
  }
551
576
  }
552
577
  /**
578
+ * Extract event label from ASCII-encoded topic (D9 chain format)
579
+ *
580
+ * D9 chain uses a format where:
581
+ * - First byte is 0x00 (null)
582
+ * - Remaining 31 bytes are ASCII characters of `ContractName::EventLabel`
583
+ * - Total is exactly 32 bytes (truncated/padded as needed)
584
+ *
585
+ * @param topic - The 32-byte topic from the event
586
+ * @returns The extracted event label, or null if not in ASCII format
587
+ */
588
+ extractEventLabelFromAsciiTopic(topic) {
589
+ if (topic.length !== 32) return null;
590
+ if (topic[0] !== 0) return null;
591
+ const ascii = new TextDecoder().decode(topic.slice(1)).replace(/\0+$/, "");
592
+ const colonIndex = ascii.lastIndexOf("::");
593
+ if (colonIndex !== -1) return ascii.slice(colonIndex + 2);
594
+ return ascii || null;
595
+ }
596
+ /**
553
597
  * Filter a batch of events and return type-safe results
554
598
  *
555
599
  * @param chainEvents - Array of chain events to filter
@@ -647,18 +691,6 @@ var ContractEventParser = class {
647
691
  for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
648
692
  return true;
649
693
  }
650
- /**
651
- * Build event signature map from metadata
652
- */
653
- static buildEventSignatureMap(metadata) {
654
- const signatures = /* @__PURE__ */ new Map();
655
- const events = metadata.spec.events;
656
- for (const event of events) {
657
- const sig = getEventSignature(event.label);
658
- signatures.set(event.label, sig);
659
- }
660
- return signatures;
661
- }
662
694
  };
663
695
  /**
664
696
  * Type guard for narrowing event types
@@ -1810,6 +1842,127 @@ function isCallType(call, label) {
1810
1842
  return call.type === label;
1811
1843
  }
1812
1844
 
1845
+ //#endregion
1846
+ //#region src/utils/fees.ts
1847
+ const WEIGHT_REF_TIME_PER_SECOND = 1000000000000n;
1848
+ const WEIGHT_FEE_COEFFICIENT = 1n;
1849
+ /**
1850
+ * Estimate the transaction cost from gas info and storage deposit
1851
+ *
1852
+ * Note: This is an approximation. Actual fees depend on chain configuration
1853
+ * and may vary slightly.
1854
+ *
1855
+ * @param gasInfo - Gas information from contract query
1856
+ * @param storageDeposit - Storage deposit amount (positive for charge, negative for refund)
1857
+ * @returns Estimated cost breakdown
1858
+ *
1859
+ * @example
1860
+ * ```typescript
1861
+ * const result = await contract.query("PSP22::transfer", { origin, args });
1862
+ * if (result.success) {
1863
+ * const cost = estimateTransactionCost(
1864
+ * { gasConsumed: result.gasConsumed, gasRequired: result.gasRequired },
1865
+ * result.storageDeposit
1866
+ * );
1867
+ * console.log(`Estimated cost: ${formatBalance(cost.total, { decimals: 12 })} D9`);
1868
+ * }
1869
+ * ```
1870
+ */
1871
+ function estimateTransactionCost(gasInfo, storageDeposit) {
1872
+ const { gasRequired } = gasInfo;
1873
+ const gasCost = gasRequired.refTime * WEIGHT_FEE_COEFFICIENT / WEIGHT_REF_TIME_PER_SECOND + gasRequired.proofSize;
1874
+ const effectiveStorageDeposit = storageDeposit > 0n ? storageDeposit : 0n;
1875
+ return {
1876
+ gasCost,
1877
+ storageDeposit: effectiveStorageDeposit,
1878
+ total: gasCost + effectiveStorageDeposit
1879
+ };
1880
+ }
1881
+ /**
1882
+ * Format gas information for human-readable display
1883
+ *
1884
+ * @param gasInfo - Gas information from contract query
1885
+ * @returns Formatted strings for ref_time and proof_size
1886
+ *
1887
+ * @example
1888
+ * ```typescript
1889
+ * const formatted = formatGasInfo(result.gasRequired);
1890
+ * console.log(`Gas: refTime=${formatted.refTime}, proofSize=${formatted.proofSize}`);
1891
+ * ```
1892
+ */
1893
+ function formatGasInfo(gasInfo) {
1894
+ return {
1895
+ refTime: formatWeight(gasInfo.refTime),
1896
+ proofSize: formatWeight(gasInfo.proofSize)
1897
+ };
1898
+ }
1899
+ /**
1900
+ * Format a single weight value with appropriate units
1901
+ */
1902
+ function formatWeight(weight) {
1903
+ if (weight >= 1000000000000n) return `${(Number(weight) / 0xe8d4a51000).toFixed(2)}T`;
1904
+ if (weight >= 1000000000n) return `${(Number(weight) / 1e9).toFixed(2)}G`;
1905
+ if (weight >= 1000000n) return `${(Number(weight) / 1e6).toFixed(2)}M`;
1906
+ if (weight >= 1000n) return `${(Number(weight) / 1e3).toFixed(2)}K`;
1907
+ return weight.toString();
1908
+ }
1909
+ /**
1910
+ * Apply a safety margin to gas limits
1911
+ *
1912
+ * It's recommended to add a small margin to gas estimates to account for
1913
+ * slight variations in execution. 10% (multiplier = 1.1) is a common choice.
1914
+ *
1915
+ * @param gas - The gas weight to adjust
1916
+ * @param multiplier - The multiplier to apply (default: 1.1 for 10% margin)
1917
+ * @returns Adjusted gas weight with margin applied
1918
+ *
1919
+ * @example
1920
+ * ```typescript
1921
+ * const result = await contract.query("PSP22::transfer", { origin, args });
1922
+ * if (result.success) {
1923
+ * // Add 10% safety margin
1924
+ * const safeGas = applyGasMargin(result.gasRequired, 1.1);
1925
+ * await contract.send("PSP22::transfer", {
1926
+ * origin,
1927
+ * args,
1928
+ * gasLimit: safeGas,
1929
+ * });
1930
+ * }
1931
+ * ```
1932
+ */
1933
+ function applyGasMargin(gas, multiplier = 1.1) {
1934
+ if (multiplier <= 0) throw new Error("Multiplier must be positive");
1935
+ const basisPoints = BigInt(Math.round(multiplier * 1e4));
1936
+ return {
1937
+ refTime: gas.refTime * basisPoints / 10000n,
1938
+ proofSize: gas.proofSize * basisPoints / 10000n
1939
+ };
1940
+ }
1941
+ /**
1942
+ * Compare two gas weights
1943
+ *
1944
+ * @param a - First gas weight
1945
+ * @param b - Second gas weight
1946
+ * @returns -1 if a < b, 0 if equal, 1 if a > b (compares refTime first, then proofSize)
1947
+ */
1948
+ function compareGasWeight(a, b) {
1949
+ if (a.refTime < b.refTime) return -1;
1950
+ if (a.refTime > b.refTime) return 1;
1951
+ if (a.proofSize < b.proofSize) return -1;
1952
+ if (a.proofSize > b.proofSize) return 1;
1953
+ return 0;
1954
+ }
1955
+ /**
1956
+ * Check if gas weight exceeds a limit
1957
+ *
1958
+ * @param gas - The gas to check
1959
+ * @param limit - The limit to compare against
1960
+ * @returns True if gas exceeds the limit in either dimension
1961
+ */
1962
+ function gasExceedsLimit(gas, limit) {
1963
+ return gas.refTime > limit.refTime || gas.proofSize > limit.proofSize;
1964
+ }
1965
+
1813
1966
  //#endregion
1814
1967
  exports.AbortedError = AbortedError;
1815
1968
  exports.ContractCallParser = ContractCallParser;
@@ -1825,10 +1978,13 @@ exports.NetworkError = NetworkError;
1825
1978
  exports.SignerError = SignerError;
1826
1979
  exports.TimeoutError = TimeoutError;
1827
1980
  exports.TransactionError = TransactionError;
1981
+ exports.applyGasMargin = applyGasMargin;
1828
1982
  exports.buildAllEventDecoders = buildAllEventDecoders;
1829
1983
  exports.buildAllMessageDecoders = buildAllMessageDecoders;
1830
1984
  exports.buildEventDecoder = buildEventDecoder;
1831
1985
  exports.buildMessageDecoder = buildMessageDecoder;
1986
+ exports.compareGasWeight = compareGasWeight;
1987
+ exports.createAsciiEventTopic = createAsciiEventTopic;
1832
1988
  exports.createCodecRegistry = createCodecRegistry;
1833
1989
  exports.createContractEventStream = createContractEventStream;
1834
1990
  exports.createD9InkContract = createD9InkContract;
@@ -1843,6 +1999,9 @@ exports.decodeResult = decodeResult;
1843
1999
  exports.encodeCall = encodeCall;
1844
2000
  exports.encodeContractCall = encodeContractCall;
1845
2001
  exports.encodeContractCallWithLimits = encodeContractCallWithLimits;
2002
+ exports.estimateTransactionCost = estimateTransactionCost;
2003
+ exports.formatGasInfo = formatGasInfo;
2004
+ exports.gasExceedsLimit = gasExceedsLimit;
1846
2005
  exports.getEventSignature = getEventSignature;
1847
2006
  exports.isCallType = isCallType;
1848
2007
  exports.isContractError = isContractError;