@d9-network/spec 0.0.12 → 0.0.14

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
@@ -7463,7 +7463,7 @@ var getMetadata2 = async (codeHash) => {
7463
7463
  * @example
7464
7464
  * ```ts
7465
7465
  * const d9Client = createD9SdkClient({
7466
- * endpoint: "wss://mainnet.d9network.com:40300",
7466
+ * endpoint: "wss://archiver.d9network.com:40300",
7467
7467
  * });
7468
7468
  *
7469
7469
  * // Query USDT balance
@@ -7584,8 +7584,392 @@ function createAccountFromPrivateKey(options) {
7584
7584
  };
7585
7585
  }
7586
7586
 
7587
+ //#endregion
7588
+ //#region src/utils/balance.ts
7589
+ /**
7590
+ * Balance formatting utilities for D9 blockchain
7591
+ */
7592
+ const D9_DECIMALS = 12;
7593
+ const D9_SYMBOL = "D9";
7594
+ const D9_SS58_PREFIX = 9;
7595
+ const USDT_DECIMALS = 2;
7596
+ const USDT_SYMBOL = "USDT";
7597
+ /**
7598
+ * Pre-configured D9 token
7599
+ */
7600
+ const D9_TOKEN = {
7601
+ decimals: D9_DECIMALS,
7602
+ symbol: D9_SYMBOL
7603
+ };
7604
+ /**
7605
+ * Pre-configured USDT token
7606
+ */
7607
+ const USDT_TOKEN = {
7608
+ decimals: USDT_DECIMALS,
7609
+ symbol: USDT_SYMBOL
7610
+ };
7611
+ /**
7612
+ * Format a raw planck value to a human-readable balance string
7613
+ *
7614
+ * @param planck - The raw balance in planck units (smallest unit)
7615
+ * @param options - Formatting options
7616
+ * @returns Formatted balance string
7617
+ *
7618
+ * @example
7619
+ * ```typescript
7620
+ * formatBalance(1_500_000_000_000n, { decimals: 12 }); // "1.5"
7621
+ * formatBalance(1_500_000_000_000n, { decimals: 12, maxDecimals: 2 }); // "1.50"
7622
+ * formatBalance(1_000_000_000_000_000n, { decimals: 12, thousandsSeparator: "," }); // "1,000"
7623
+ * ```
7624
+ */
7625
+ function formatBalance(planck, options = {}) {
7626
+ const { decimals = D9_DECIMALS, maxDecimals = 4, trimTrailingZeros = true, thousandsSeparator } = options;
7627
+ if (decimals < 0 || decimals > 30) throw new Error("Decimals must be between 0 and 30");
7628
+ const divisor = 10n ** BigInt(decimals);
7629
+ const isNegative = planck < 0n;
7630
+ const absolutePlanck = isNegative ? -planck : planck;
7631
+ const wholePart = absolutePlanck / divisor;
7632
+ const fractionalPart = absolutePlanck % divisor;
7633
+ let wholeStr = wholePart.toString();
7634
+ if (thousandsSeparator && wholeStr.length > 3) wholeStr = wholeStr.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsSeparator);
7635
+ if (decimals === 0 || maxDecimals === 0) return isNegative ? `-${wholeStr}` : wholeStr;
7636
+ let fractionalStr = fractionalPart.toString().padStart(decimals, "0");
7637
+ if (fractionalStr.length > maxDecimals) fractionalStr = fractionalStr.slice(0, maxDecimals);
7638
+ if (trimTrailingZeros) fractionalStr = fractionalStr.replace(/0+$/, "");
7639
+ const prefix = isNegative ? "-" : "";
7640
+ if (fractionalStr === "") return `${prefix}${wholeStr}`;
7641
+ return `${prefix}${wholeStr}.${fractionalStr}`;
7642
+ }
7643
+ /**
7644
+ * Parse a human-readable amount string to planck units
7645
+ *
7646
+ * @param amount - The amount as a string or number
7647
+ * @param options - Parse options
7648
+ * @returns The amount in planck units (bigint)
7649
+ *
7650
+ * @example
7651
+ * ```typescript
7652
+ * parseAmount("1.5", { decimals: 12 }); // 1_500_000_000_000n
7653
+ * parseAmount(1.5, { decimals: 12 }); // 1_500_000_000_000n
7654
+ * parseAmount("1,000.50", { decimals: 12 }); // 1_000_500_000_000_000n
7655
+ * ```
7656
+ */
7657
+ function parseAmount(amount, options = {}) {
7658
+ const { decimals = D9_DECIMALS } = options;
7659
+ if (decimals < 0 || decimals > 30) throw new Error("Decimals must be between 0 and 30");
7660
+ let amountStr = String(amount).replace(/,/g, "").trim();
7661
+ const isNegative = amountStr.startsWith("-");
7662
+ if (isNegative) amountStr = amountStr.slice(1);
7663
+ if (!/^\d*\.?\d*$/.test(amountStr) || amountStr === "" || amountStr === ".") throw new Error(`Invalid amount format: ${amount}`);
7664
+ const [wholePart = "0", fractionalPart = ""] = amountStr.split(".");
7665
+ if (fractionalPart.length > decimals) throw new Error(`Amount has more decimal places (${fractionalPart.length}) than supported (${decimals})`);
7666
+ const planckStr = wholePart + fractionalPart.padEnd(decimals, "0");
7667
+ const planck = BigInt(planckStr);
7668
+ return isNegative ? -planck : planck;
7669
+ }
7670
+ /**
7671
+ * Format a token amount with symbol
7672
+ *
7673
+ * @param planck - The raw balance in planck units
7674
+ * @param token - Token configuration
7675
+ * @param options - Additional formatting options
7676
+ * @returns Formatted string with token symbol
7677
+ *
7678
+ * @example
7679
+ * ```typescript
7680
+ * formatTokenAmount(1_500_000_000_000n, D9_TOKEN); // "1.5 D9"
7681
+ * formatTokenAmount(1000n, USDT_TOKEN); // "10 USDT"
7682
+ * ```
7683
+ */
7684
+ function formatTokenAmount(planck, token, options = {}) {
7685
+ return `${formatBalance(planck, {
7686
+ ...options,
7687
+ decimals: token.decimals
7688
+ })} ${token.symbol}`;
7689
+ }
7690
+
7691
+ //#endregion
7692
+ //#region src/wallet/validation.ts
7693
+ /**
7694
+ * Address validation utilities for D9 blockchain
7695
+ */
7696
+ /**
7697
+ * Check if a value is a valid SS58 address
7698
+ *
7699
+ * @param address - The value to check
7700
+ * @returns True if the value is a valid SS58 address
7701
+ *
7702
+ * @example
7703
+ * ```typescript
7704
+ * isValidAddress("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"); // true
7705
+ * isValidAddress("invalid"); // false
7706
+ * isValidAddress(null); // false
7707
+ * ```
7708
+ */
7709
+ function isValidAddress(address) {
7710
+ if (typeof address !== "string" || address.length === 0) return false;
7711
+ try {
7712
+ (0, _polkadot_labs_hdkd_helpers.ss58Decode)(address);
7713
+ return true;
7714
+ } catch {
7715
+ return false;
7716
+ }
7717
+ }
7718
+ /**
7719
+ * Check if a value is a valid D9 address (SS58 prefix 9)
7720
+ *
7721
+ * @param address - The value to check
7722
+ * @returns True if the value is a valid D9 address
7723
+ *
7724
+ * @example
7725
+ * ```typescript
7726
+ * isValidD9Address("XYZd9..."); // true (if valid D9 prefix)
7727
+ * isValidD9Address("5GrwvaEF..."); // false (Polkadot prefix)
7728
+ * ```
7729
+ */
7730
+ function isValidD9Address(address) {
7731
+ return isValidAddressForNetwork(address, D9_SS58_PREFIX);
7732
+ }
7733
+ /**
7734
+ * Check if a value is a valid address for a specific network
7735
+ *
7736
+ * @param address - The value to check
7737
+ * @param expectedPrefix - The expected SS58 prefix
7738
+ * @returns True if the value is a valid address with the expected prefix
7739
+ *
7740
+ * @example
7741
+ * ```typescript
7742
+ * isValidAddressForNetwork(address, 0); // Polkadot
7743
+ * isValidAddressForNetwork(address, 2); // Kusama
7744
+ * isValidAddressForNetwork(address, 9); // D9
7745
+ * ```
7746
+ */
7747
+ function isValidAddressForNetwork(address, expectedPrefix) {
7748
+ if (typeof address !== "string" || address.length === 0) return false;
7749
+ try {
7750
+ const [, prefix] = (0, _polkadot_labs_hdkd_helpers.ss58Decode)(address);
7751
+ return prefix === expectedPrefix;
7752
+ } catch {
7753
+ return false;
7754
+ }
7755
+ }
7756
+ /**
7757
+ * Get the SS58 prefix of an address
7758
+ *
7759
+ * @param address - The SS58 address
7760
+ * @returns The SS58 prefix
7761
+ * @throws Error if the address is invalid
7762
+ *
7763
+ * @example
7764
+ * ```typescript
7765
+ * getAddressPrefix("5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY"); // 42 (Substrate generic)
7766
+ * ```
7767
+ */
7768
+ function getAddressPrefix(address) {
7769
+ const [, prefix] = (0, _polkadot_labs_hdkd_helpers.ss58Decode)(address);
7770
+ return prefix;
7771
+ }
7772
+ /**
7773
+ * Compare two addresses for equality (same public key)
7774
+ *
7775
+ * Addresses with different SS58 prefixes can represent the same account.
7776
+ * This function compares the underlying public keys.
7777
+ *
7778
+ * @param a - First address
7779
+ * @param b - Second address
7780
+ * @returns True if both addresses represent the same public key
7781
+ *
7782
+ * @example
7783
+ * ```typescript
7784
+ * // Same account, different network formats
7785
+ * const polkadotAddr = "15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5";
7786
+ * const genericAddr = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY";
7787
+ * addressesEqual(polkadotAddr, genericAddr); // true
7788
+ * ```
7789
+ */
7790
+ function addressesEqual(a, b) {
7791
+ try {
7792
+ const [publicKeyA] = (0, _polkadot_labs_hdkd_helpers.ss58Decode)(a);
7793
+ const [publicKeyB] = (0, _polkadot_labs_hdkd_helpers.ss58Decode)(b);
7794
+ if (publicKeyA.length !== publicKeyB.length) return false;
7795
+ for (let i = 0; i < publicKeyA.length; i++) if (publicKeyA[i] !== publicKeyB[i]) return false;
7796
+ return true;
7797
+ } catch {
7798
+ return false;
7799
+ }
7800
+ }
7801
+ /**
7802
+ * Convert an address to a specific SS58 format
7803
+ *
7804
+ * @param address - The SS58 address
7805
+ * @param targetPrefix - The target SS58 prefix
7806
+ * @returns The address encoded with the target prefix
7807
+ * @throws Error if the address is invalid
7808
+ *
7809
+ * @example
7810
+ * ```typescript
7811
+ * const d9Address = toNetworkAddress("5GrwvaEF...", 9);
7812
+ * ```
7813
+ */
7814
+ function toNetworkAddress(address, targetPrefix) {
7815
+ const [publicKey] = (0, _polkadot_labs_hdkd_helpers.ss58Decode)(address);
7816
+ return (0, _polkadot_labs_hdkd_helpers.ss58Encode)(publicKey, targetPrefix);
7817
+ }
7818
+ /**
7819
+ * Convert an address to D9 format
7820
+ *
7821
+ * @param address - The SS58 address
7822
+ * @returns The address encoded with D9 prefix (9)
7823
+ *
7824
+ * @example
7825
+ * ```typescript
7826
+ * const d9Address = toD9Address("5GrwvaEF...");
7827
+ * ```
7828
+ */
7829
+ function toD9Address(address) {
7830
+ return toNetworkAddress(address, D9_SS58_PREFIX);
7831
+ }
7832
+
7833
+ //#endregion
7834
+ //#region src/utils/time.ts
7835
+ /**
7836
+ * Block time utilities for D9 blockchain
7837
+ */
7838
+ const D9_BLOCK_TIME_MS = 3e3;
7839
+ const BLOCKS_PER_MINUTE = 20;
7840
+ const BLOCKS_PER_HOUR = 1200;
7841
+ const BLOCKS_PER_DAY = 28800;
7842
+ const BLOCKS_PER_WEEK = 201600;
7843
+ /**
7844
+ * Convert milliseconds to blocks
7845
+ *
7846
+ * @param ms - Duration in milliseconds
7847
+ * @returns Number of blocks (rounded down)
7848
+ *
7849
+ * @example
7850
+ * ```typescript
7851
+ * msToBlocks(60_000); // 20 blocks (1 minute)
7852
+ * msToBlocks(3_600_000); // 1200 blocks (1 hour)
7853
+ * ```
7854
+ */
7855
+ function msToBlocks(ms) {
7856
+ if (ms < 0) throw new Error("Duration cannot be negative");
7857
+ return Math.floor(ms / D9_BLOCK_TIME_MS);
7858
+ }
7859
+ /**
7860
+ * Convert blocks to milliseconds
7861
+ *
7862
+ * @param blocks - Number of blocks
7863
+ * @returns Duration in milliseconds
7864
+ *
7865
+ * @example
7866
+ * ```typescript
7867
+ * blocksToMs(20); // 60_000 (1 minute)
7868
+ * blocksToMs(1200); // 3_600_000 (1 hour)
7869
+ * ```
7870
+ */
7871
+ function blocksToMs(blocks) {
7872
+ if (blocks < 0) throw new Error("Block count cannot be negative");
7873
+ return blocks * D9_BLOCK_TIME_MS;
7874
+ }
7875
+ /**
7876
+ * Estimate the block number at a target time
7877
+ *
7878
+ * @param targetTime - The target time to estimate block for
7879
+ * @param currentBlock - The current block number
7880
+ * @param currentTime - The current time (default: now)
7881
+ * @returns Estimated block number at target time
7882
+ *
7883
+ * @example
7884
+ * ```typescript
7885
+ * const targetBlock = estimateBlockAtTime(
7886
+ * new Date(Date.now() + 3_600_000), // 1 hour from now
7887
+ * 1000, // current block
7888
+ * ); // ~2200
7889
+ * ```
7890
+ */
7891
+ function estimateBlockAtTime(targetTime, currentBlock, currentTime = /* @__PURE__ */ new Date()) {
7892
+ const timeDiffMs = targetTime.getTime() - currentTime.getTime();
7893
+ const blockDiff = Math.floor(timeDiffMs / D9_BLOCK_TIME_MS);
7894
+ return Math.max(0, currentBlock + blockDiff);
7895
+ }
7896
+ /**
7897
+ * Estimate the time at a target block
7898
+ *
7899
+ * @param targetBlock - The target block number
7900
+ * @param currentBlock - The current block number
7901
+ * @param currentTime - The current time (default: now)
7902
+ * @returns Estimated time at target block
7903
+ *
7904
+ * @example
7905
+ * ```typescript
7906
+ * const unlockTime = estimateTimeAtBlock(
7907
+ * 2200, // target block
7908
+ * 1000, // current block
7909
+ * ); // ~1 hour from now
7910
+ * ```
7911
+ */
7912
+ function estimateTimeAtBlock(targetBlock, currentBlock, currentTime = /* @__PURE__ */ new Date()) {
7913
+ const timeDiffMs = (targetBlock - currentBlock) * D9_BLOCK_TIME_MS;
7914
+ return new Date(currentTime.getTime() + timeDiffMs);
7915
+ }
7916
+ /**
7917
+ * Calculate the number of blocks until a target time
7918
+ *
7919
+ * @param targetTime - The target time
7920
+ * @param currentBlock - The current block number
7921
+ * @param currentTime - The current time (default: now)
7922
+ * @returns Number of blocks until target time (negative if in the past)
7923
+ *
7924
+ * @example
7925
+ * ```typescript
7926
+ * const blocksRemaining = blocksUntil(unlockTime, currentBlock);
7927
+ * if (blocksRemaining > 0) {
7928
+ * console.log(`${blocksRemaining} blocks until unlock`);
7929
+ * }
7930
+ * ```
7931
+ */
7932
+ function blocksUntil(targetTime, currentBlock, currentTime = /* @__PURE__ */ new Date()) {
7933
+ return estimateBlockAtTime(targetTime, currentBlock, currentTime) - currentBlock;
7934
+ }
7935
+ /**
7936
+ * Format a block duration as a human-readable string
7937
+ *
7938
+ * @param blocks - Number of blocks
7939
+ * @param options - Formatting options
7940
+ * @returns Human-readable duration string
7941
+ *
7942
+ * @example
7943
+ * ```typescript
7944
+ * formatBlockDuration(20); // "1 minute"
7945
+ * formatBlockDuration(1200); // "1 hour"
7946
+ * formatBlockDuration(BLOCKS_PER_DAY); // "1 day"
7947
+ * formatBlockDuration(30000, { short: true }); // "1d 1h"
7948
+ * ```
7949
+ */
7950
+ function formatBlockDuration(blocks, options = {}) {
7951
+ const { short = false, maxUnits = 2 } = options;
7952
+ if (blocks < 0) throw new Error("Block count cannot be negative");
7953
+ if (blocks === 0) return short ? "0s" : "0 seconds";
7954
+ const totalSeconds = Math.floor(blocks * D9_BLOCK_TIME_MS / 1e3);
7955
+ const days = Math.floor(totalSeconds / 86400);
7956
+ const hours = Math.floor(totalSeconds % 86400 / 3600);
7957
+ const minutes = Math.floor(totalSeconds % 3600 / 60);
7958
+ const seconds = totalSeconds % 60;
7959
+ const parts = [];
7960
+ if (days > 0) parts.push(short ? `${days}d` : `${days} ${days === 1 ? "day" : "days"}`);
7961
+ if (hours > 0) parts.push(short ? `${hours}h` : `${hours} ${hours === 1 ? "hour" : "hours"}`);
7962
+ if (minutes > 0) parts.push(short ? `${minutes}m` : `${minutes} ${minutes === 1 ? "minute" : "minutes"}`);
7963
+ if (seconds > 0 && parts.length < maxUnits) parts.push(short ? `${seconds}s` : `${seconds} ${seconds === 1 ? "second" : "seconds"}`);
7964
+ return parts.slice(0, maxUnits).join(short ? " " : ", ");
7965
+ }
7966
+
7587
7967
  //#endregion
7588
7968
  exports.ArithmeticError = ArithmeticError;
7969
+ exports.BLOCKS_PER_DAY = BLOCKS_PER_DAY;
7970
+ exports.BLOCKS_PER_HOUR = BLOCKS_PER_HOUR;
7971
+ exports.BLOCKS_PER_MINUTE = BLOCKS_PER_MINUTE;
7972
+ exports.BLOCKS_PER_WEEK = BLOCKS_PER_WEEK;
7589
7973
  exports.BalanceStatus = BalanceStatus;
7590
7974
  exports.BalancesTypesReasons = BalancesTypesReasons;
7591
7975
  Object.defineProperty(exports, 'ContractEventParser', {
@@ -7594,6 +7978,11 @@ Object.defineProperty(exports, 'ContractEventParser', {
7594
7978
  return _d9_network_ink.ContractEventParser;
7595
7979
  }
7596
7980
  });
7981
+ exports.D9_BLOCK_TIME_MS = D9_BLOCK_TIME_MS;
7982
+ exports.D9_DECIMALS = D9_DECIMALS;
7983
+ exports.D9_SS58_PREFIX = D9_SS58_PREFIX;
7984
+ exports.D9_SYMBOL = D9_SYMBOL;
7985
+ exports.D9_TOKEN = D9_TOKEN;
7597
7986
  exports.DigestItem = DigestItem;
7598
7987
  exports.DispatchClass = DispatchClass;
7599
7988
  exports.GrandpaEquivocation = GrandpaEquivocation;
@@ -7605,6 +7994,12 @@ exports.SessionEvent = SessionEvent;
7605
7994
  exports.TransactionPaymentEvent = TransactionPaymentEvent;
7606
7995
  exports.TransactionPaymentReleases = TransactionPaymentReleases;
7607
7996
  exports.TransactionalError = TransactionalError;
7997
+ exports.USDT_DECIMALS = USDT_DECIMALS;
7998
+ exports.USDT_SYMBOL = USDT_SYMBOL;
7999
+ exports.USDT_TOKEN = USDT_TOKEN;
8000
+ exports.addressesEqual = addressesEqual;
8001
+ exports.blocksToMs = blocksToMs;
8002
+ exports.blocksUntil = blocksUntil;
7608
8003
  exports.bytesToHex = bytesToHex;
7609
8004
  exports.contracts = contracts_exports;
7610
8005
  exports.createAccountFromMnemonic = createAccountFromMnemonic;
@@ -7630,16 +8025,29 @@ Object.defineProperty(exports, 'createPSP22TransferStream', {
7630
8025
  });
7631
8026
  exports.createSr25519SignerFromKeypair = createSr25519SignerFromKeypair;
7632
8027
  exports.d9 = d9_default;
8028
+ exports.estimateBlockAtTime = estimateBlockAtTime;
8029
+ exports.estimateTimeAtBlock = estimateTimeAtBlock;
8030
+ exports.formatBalance = formatBalance;
8031
+ exports.formatBlockDuration = formatBlockDuration;
8032
+ exports.formatTokenAmount = formatTokenAmount;
7633
8033
  exports.generateMnemonic = generateMnemonic;
8034
+ exports.getAddressPrefix = getAddressPrefix;
7634
8035
  exports.getMetadata = getMetadata2;
7635
8036
  exports.hexToBytes = hexToBytes;
7636
8037
  exports.isHexString = isHexString;
8038
+ exports.isValidAddress = isValidAddress;
8039
+ exports.isValidAddressForNetwork = isValidAddressForNetwork;
8040
+ exports.isValidD9Address = isValidD9Address;
7637
8041
  exports.mnemonicToMiniSecret = mnemonicToMiniSecret;
8042
+ exports.msToBlocks = msToBlocks;
8043
+ exports.parseAmount = parseAmount;
7638
8044
  exports.sr25519AddressFromKeypair = sr25519AddressFromKeypair;
7639
8045
  exports.sr25519AddressFromSecretKeyHex = sr25519AddressFromSecretKeyHex;
7640
8046
  exports.sr25519DeriveFromMiniSecret = sr25519DeriveFromMiniSecret;
7641
8047
  exports.sr25519KeypairFromMiniSecret = sr25519KeypairFromMiniSecret;
7642
8048
  exports.ss58DecodePublicKey = ss58DecodePublicKey;
7643
8049
  exports.ss58Reencode = ss58Reencode;
8050
+ exports.toD9Address = toD9Address;
8051
+ exports.toNetworkAddress = toNetworkAddress;
7644
8052
  exports.validateMnemonic = validateMnemonic;
7645
8053
  //# sourceMappingURL=index.cjs.map