@d9-network/ink 0.0.6 → 0.0.7
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 +174 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +132 -5
- package/dist/index.d.mts +132 -5
- package/dist/index.mjs +169 -16
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
521
|
-
|
|
522
|
-
|
|
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);
|
|
@@ -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;
|