@steemit/steem-js 1.0.13 → 1.0.15

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
@@ -13858,6 +13858,20 @@ class PublicKey {
13858
13858
  const secp256k1$1 = new ellipticExports.ec('secp256k1');
13859
13859
  const G = secp256k1$1.g;
13860
13860
  const n = new BN(secp256k1$1.n.toString());
13861
+ /**
13862
+ * Constant-time buffer comparison to prevent timing attacks.
13863
+ * Returns true only if a.length === b.length and a[i] === b[i] for all i.
13864
+ */
13865
+ function constantTimeCompare(a, b) {
13866
+ if (a.length !== b.length) {
13867
+ return false;
13868
+ }
13869
+ let result = 0;
13870
+ for (let i = 0; i < a.length; i++) {
13871
+ result |= a[i] ^ b[i];
13872
+ }
13873
+ return result === 0;
13874
+ }
13861
13875
  class PrivateKey {
13862
13876
  /**
13863
13877
  * @private see static functions
@@ -13870,11 +13884,8 @@ class PrivateKey {
13870
13884
  if (!Buffer.isBuffer(buf)) {
13871
13885
  throw new Error("Expecting parameter to be a Buffer type");
13872
13886
  }
13873
- if (32 !== buf.length) {
13874
- debug.warn(`WARN: Expecting 32 bytes, instead got ${buf.length}, stack trace:`, new Error().stack);
13875
- }
13876
- if (buf.length === 0) {
13877
- throw new Error("Empty buffer");
13887
+ if (buf.length !== 32) {
13888
+ throw new Error(`Invalid private key buffer: expected 32 bytes, got ${buf.length}`);
13878
13889
  }
13879
13890
  return new PrivateKey(new BN(buf));
13880
13891
  }
@@ -13899,21 +13910,33 @@ class PrivateKey {
13899
13910
  * @return {string} Wallet Import Format (still a secret, Not encrypted)
13900
13911
  */
13901
13912
  static fromWif(private_wif) {
13902
- const private_wif_buffer = Buffer.from(bs58.decode(private_wif));
13913
+ if (!private_wif || typeof private_wif !== 'string') {
13914
+ throw new Error('Invalid WIF: empty or not a string');
13915
+ }
13916
+ let private_wif_buffer;
13917
+ try {
13918
+ private_wif_buffer = Buffer.from(bs58.decode(private_wif));
13919
+ }
13920
+ catch {
13921
+ throw new Error('Invalid WIF: failed to decode base58');
13922
+ }
13923
+ // Valid WIF: 1 byte version + 32 bytes key + 4 bytes checksum = 37 bytes
13924
+ if (private_wif_buffer.length !== 37) {
13925
+ throw new Error(`Invalid WIF: expected 37 bytes, got ${private_wif_buffer.length}`);
13926
+ }
13903
13927
  const version = private_wif_buffer.readUInt8(0);
13904
- if (version !== 0x80)
13905
- throw new Error(`Expected version ${0x80}, instead got ${version}`);
13906
- // checksum includes the version
13907
- const private_key = private_wif_buffer.slice(0, -4);
13908
- const checksum = private_wif_buffer.slice(-4);
13909
- let new_checksum = sha256$1(private_key);
13928
+ if (version !== 0x80) {
13929
+ throw new Error(`Invalid WIF: expected version 0x80, got 0x${version.toString(16)}`);
13930
+ }
13931
+ const private_key = private_wif_buffer.slice(1, 33);
13932
+ const checksum = private_wif_buffer.slice(33);
13933
+ let new_checksum = sha256$1(Buffer.concat([Buffer.from([0x80]), private_key]));
13910
13934
  new_checksum = sha256$1(new_checksum);
13911
13935
  new_checksum = new_checksum.slice(0, 4);
13912
- if (checksum.toString() !== new_checksum.toString()) {
13936
+ if (!constantTimeCompare(checksum, Buffer.from(new_checksum))) {
13913
13937
  throw new Error('Invalid WIF key (checksum miss-match)');
13914
13938
  }
13915
- private_key.writeUInt8(0x80, 0);
13916
- return PrivateKey.fromBuffer(private_key.slice(1));
13939
+ return PrivateKey.fromBuffer(private_key);
13917
13940
  }
13918
13941
  toWif() {
13919
13942
  const private_key = this.toBuffer();
@@ -14292,18 +14315,21 @@ function calcPubKeyRecoveryParam(curve, e, signature, Q) {
14292
14315
  }
14293
14316
  catch (error) {
14294
14317
  // try next value
14295
- console.debug(`Recovery attempt ${i} failed:`, error.message);
14318
+ if (process.env.NODE_ENV === 'development') {
14319
+ console.debug(`Recovery attempt ${i} failed:`, error.message);
14320
+ }
14296
14321
  }
14297
14322
  }
14298
- // Additional debugging
14299
- console.debug('All recovery attempts failed. Signature:', {
14300
- r: signature.r.toString(16),
14301
- s: signature.s.toString(16)
14302
- });
14303
- console.debug('Expected public key:', {
14304
- x: Q.getX().toString(16),
14305
- y: Q.getY().toString(16)
14306
- });
14323
+ if (process.env.NODE_ENV === 'development') {
14324
+ console.debug('All recovery attempts failed. Signature:', {
14325
+ r: signature.r.toString(16),
14326
+ s: signature.s.toString(16)
14327
+ });
14328
+ console.debug('Expected public key:', {
14329
+ x: Q.getX().toString(16),
14330
+ y: Q.getY().toString(16)
14331
+ });
14332
+ }
14307
14333
  throw new Error('Unable to find valid recovery factor');
14308
14334
  }
14309
14335
 
@@ -14355,9 +14381,10 @@ class Signature {
14355
14381
  const d = privKey.d;
14356
14382
  let ecsignature;
14357
14383
  let nonce = 0;
14384
+ const MAX_NONCE_ATTEMPTS = 1000;
14358
14385
  // Match old-steem-js behavior: find canonical signature (lenR === 32 && lenS === 32)
14359
14386
  // Based on C++ is_fc_canonical logic
14360
- while (true) {
14387
+ while (nonce < MAX_NONCE_ATTEMPTS) {
14361
14388
  ecsignature = sign$3(secp256k1, buf_sha256, d, nonce++);
14362
14389
  const rBa = ecsignature.r.toArrayLike(Buffer, 'be', 32);
14363
14390
  const sBa = ecsignature.s.toArrayLike(Buffer, 'be', 32);
@@ -14374,6 +14401,9 @@ class Signature {
14374
14401
  console.debug("WARN: " + nonce + " attempts to find canonical signature");
14375
14402
  }
14376
14403
  }
14404
+ if (nonce >= MAX_NONCE_ATTEMPTS || ecsignature === undefined) {
14405
+ throw new Error('Failed to find canonical signature after maximum attempts');
14406
+ }
14377
14407
  const i = calcPubKeyRecoveryParam(secp256k1, new BN(buf_sha256), ecsignature, privKey.toPublic().Q);
14378
14408
  // Use recovery byte 31-34 (instead of 27-30) to be compatible with dsteem
14379
14409
  // dsteem expects: recovery = byte - 31, so byte = recovery + 31
@@ -14674,7 +14704,11 @@ async function validate(request, verify) {
14674
14704
  if (Number.isNaN(timestamp)) {
14675
14705
  throw new Error('Invalid timestamp');
14676
14706
  }
14677
- if (Date.now() - timestamp > 60 * 1000) {
14707
+ const now = Date.now();
14708
+ const timeDiff = Math.abs(now - timestamp);
14709
+ const SIGNATURE_VALIDITY_MS = 60 * 1000;
14710
+ const MAX_CLOCK_SKEW_MS = 5 * 60 * 1000;
14711
+ if (timeDiff > SIGNATURE_VALIDITY_MS + MAX_CLOCK_SKEW_MS) {
14678
14712
  throw new Error('Signature expired');
14679
14713
  }
14680
14714
  const message = hashMessage(signed.timestamp, signed.account, request.method, signed.params, nonce);
@@ -15649,6 +15683,37 @@ class BaseTransport extends events.EventEmitter {
15649
15683
  }
15650
15684
 
15651
15685
  // @ts-expect-error: No types for 'retry'
15686
+ /** Detect Node.js for optional undici Agent (custom TLS). */
15687
+ const isNode = typeof process !== 'undefined' &&
15688
+ typeof process.versions === 'object' &&
15689
+ typeof process.versions.node === 'string';
15690
+ /**
15691
+ * Build RequestInit for fetch. In Node when options.httpsOptions is set, inject undici Agent as dispatcher.
15692
+ */
15693
+ async function buildFetchOptions(body, options) {
15694
+ const init = {
15695
+ method: 'POST',
15696
+ headers: {
15697
+ 'Content-Type': 'application/json',
15698
+ 'Accept': 'application/json'
15699
+ },
15700
+ body
15701
+ };
15702
+ if (isNode && options.httpsOptions) {
15703
+ // Node 18+ built-in fetch uses undici; custom TLS via node:undici Agent (built-in, no package)
15704
+ // @ts-expect-error - node:undici is Node built-in, not in @types/node
15705
+ const { Agent } = await import('node:undici');
15706
+ const opts = options.httpsOptions;
15707
+ const agent = new Agent({
15708
+ connect: {
15709
+ rejectUnauthorized: opts.rejectUnauthorized,
15710
+ ca: opts.ca
15711
+ }
15712
+ });
15713
+ init.dispatcher = agent;
15714
+ }
15715
+ return init;
15716
+ }
15652
15717
  /**
15653
15718
  * Extended Error type for JSON-RPC errors
15654
15719
  */
@@ -15668,29 +15733,22 @@ class JsonRpcError extends Error {
15668
15733
  * @param request - The JSON-RPC request object
15669
15734
  * @param fetchMethod - Optional fetch implementation (defaults to global fetch)
15670
15735
  * @param timeoutMs - Request timeout in milliseconds (default: 30000)
15736
+ * @param httpsOptions - Optional TLS options (Node.js only): rejectUnauthorized, ca
15671
15737
  * @returns Promise resolving to the JSON-RPC result
15672
15738
  */
15673
- const jsonRpc = async (url, request, fetchMethod = fetch, timeoutMs = 30000) => {
15739
+ const jsonRpc = async (url, request, fetchMethod = fetch, timeoutMs = 30000, httpsOptions) => {
15674
15740
  const payload = {
15675
15741
  jsonrpc: '2.0',
15676
15742
  ...request
15677
15743
  };
15678
15744
  let timeoutId = null;
15679
- // Create a promise that will reject after the timeout
15680
15745
  const timeoutPromise = new Promise((_, reject) => {
15681
15746
  timeoutId = setTimeout(() => {
15682
15747
  reject(new Error(`Request timeout after ${timeoutMs}ms`));
15683
15748
  }, timeoutMs);
15684
15749
  });
15685
- // Create the fetch promise
15686
- const fetchPromise = fetchMethod(url, {
15687
- method: 'POST',
15688
- headers: {
15689
- 'Content-Type': 'application/json',
15690
- 'Accept': 'application/json'
15691
- },
15692
- body: JSON.stringify(payload)
15693
- })
15750
+ const fetchOptions = await buildFetchOptions(JSON.stringify(payload), { httpsOptions });
15751
+ const fetchPromise = fetchMethod(url, fetchOptions)
15694
15752
  .then(async (res) => {
15695
15753
  if (!res.ok) {
15696
15754
  throw new Error(`HTTP ${res.status}: ${res.statusText}`);
@@ -15741,71 +15799,56 @@ class HttpTransport extends BaseTransport {
15741
15799
  const params = [api, data.method, data.params];
15742
15800
  const isBroadcast = this.isBroadcastOperation(data.method);
15743
15801
  const retryOptions = this.options.retry;
15744
- // Note: timeout handling is done via AbortController in jsonRpc function
15745
- if (!isBroadcast && retryOptions) {
15746
- const operation = typeof retryOptions === 'object' ? retry.operation(retryOptions) : retry.operation();
15747
- operation.attempt((currentAttempt) => {
15748
- fetchMethod(url, {
15749
- method: 'POST',
15750
- body: JSON.stringify({
15751
- jsonrpc: '2.0',
15752
- method: 'call',
15753
- params,
15754
- id
15755
- }),
15756
- headers: { 'Content-Type': 'application/json' },
15757
- })
15758
- .then(async (res) => {
15759
- if (!res.ok) {
15760
- throw new Error(`HTTP ${res.status}: ${res.statusText}`);
15761
- }
15762
- return res.json();
15763
- })
15802
+ const body = JSON.stringify({
15803
+ jsonrpc: '2.0',
15804
+ method: 'call',
15805
+ params,
15806
+ id
15807
+ });
15808
+ const doRequest = (fetchOpts) => fetchMethod(url, fetchOpts)
15809
+ .then(async (res) => {
15810
+ if (!res.ok) {
15811
+ throw new Error(`HTTP ${res.status}: ${res.statusText}`);
15812
+ }
15813
+ return res.json();
15814
+ });
15815
+ const runWithOptions = (fetchOpts) => {
15816
+ if (!isBroadcast && retryOptions) {
15817
+ const operation = typeof retryOptions === 'object' ? retry.operation(retryOptions) : retry.operation();
15818
+ operation.attempt((currentAttempt) => {
15819
+ doRequest(fetchOpts)
15820
+ .then((result) => {
15821
+ if (result.error) {
15822
+ const error = new JsonRpcError(result.error.message || 'JSON-RPC error', result.error.code, result.error.data);
15823
+ callback(error, undefined, currentAttempt);
15824
+ }
15825
+ else {
15826
+ callback(null, result.result, currentAttempt);
15827
+ }
15828
+ }, (error) => {
15829
+ if (operation.retry(error)) {
15830
+ return;
15831
+ }
15832
+ callback(operation.mainError(), undefined, currentAttempt);
15833
+ });
15834
+ });
15835
+ }
15836
+ else {
15837
+ doRequest(fetchOpts)
15764
15838
  .then((result) => {
15765
- // Check for JSON-RPC errors
15766
15839
  if (result.error) {
15767
15840
  const error = new JsonRpcError(result.error.message || 'JSON-RPC error', result.error.code, result.error.data);
15768
- callback(error, undefined, currentAttempt);
15841
+ callback(error, undefined, 1);
15769
15842
  }
15770
15843
  else {
15771
- callback(null, result.result, currentAttempt);
15844
+ callback(null, result.result, 1);
15772
15845
  }
15773
- }, (error) => {
15774
- if (operation.retry(error)) {
15775
- return;
15776
- }
15777
- callback(operation.mainError(), undefined, currentAttempt);
15778
- });
15779
- });
15780
- }
15781
- else {
15782
- fetchMethod(url, {
15783
- method: 'POST',
15784
- body: JSON.stringify({
15785
- jsonrpc: '2.0',
15786
- method: 'call',
15787
- params,
15788
- id
15789
- }),
15790
- headers: { 'Content-Type': 'application/json' }
15791
- })
15792
- .then(async (res) => {
15793
- if (!res.ok) {
15794
- throw new Error(`HTTP ${res.status}: ${res.statusText}`);
15795
- }
15796
- return res.json();
15797
- })
15798
- .then((result) => {
15799
- // Check for JSON-RPC errors
15800
- if (result.error) {
15801
- const error = new JsonRpcError(result.error.message || 'JSON-RPC error', result.error.code, result.error.data);
15802
- callback(error, undefined, 1);
15803
- }
15804
- else {
15805
- callback(null, result.result, 1);
15806
- }
15807
- }, (error) => callback(error instanceof Error ? error : new Error(String(error)), undefined, 1));
15808
- }
15846
+ }, (error) => callback(error instanceof Error ? error : new Error(String(error)), undefined, 1));
15847
+ }
15848
+ };
15849
+ buildFetchOptions(body, this.options)
15850
+ .then(runWithOptions)
15851
+ .catch((err) => callback(err instanceof Error ? err : new Error(String(err)), undefined, 1));
15809
15852
  }
15810
15853
  }
15811
15854
 
@@ -22083,7 +22126,7 @@ if (typeof BigInt === "function") {
22083
22126
  * Serialize a transaction to binary format for Steem blockchain
22084
22127
  * This is a simplified implementation that handles the basic structure
22085
22128
  */
22086
- function serializeTransaction$1(trx) {
22129
+ function serializeTransaction(trx) {
22087
22130
  const bb = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
22088
22131
  const trxObj = trx;
22089
22132
  // Write ref_block_num (uint16)
@@ -22113,7 +22156,7 @@ function serializeTransaction$1(trx) {
22113
22156
  const operations = (Array.isArray(trxObj.operations) ? trxObj.operations : []);
22114
22157
  bb.writeVarint32(operations.length);
22115
22158
  for (const op of operations) {
22116
- serializeOperation$1(bb, op);
22159
+ serializeOperation(bb, op);
22117
22160
  }
22118
22161
  // Write extensions (set of future_extensions, which is void/empty)
22119
22162
  bb.writeVarint32(0); // Empty set
@@ -22142,7 +22185,7 @@ function serializeTransaction$1(trx) {
22142
22185
  /**
22143
22186
  * Serialize an operation to binary format
22144
22187
  */
22145
- function serializeOperation$1(bb, op) {
22188
+ function serializeOperation(bb, op) {
22146
22189
  if (!Array.isArray(op) || op.length !== 2) {
22147
22190
  throw new Error('Operation must be an array of [operation_type, operation_data]');
22148
22191
  }
@@ -23074,7 +23117,7 @@ function serializeCommentOptions(bb, data) {
23074
23117
  bb.writeUint16(dataObj.percent_steem_dollars ?? 0);
23075
23118
  serializeBool(bb, dataObj.allow_votes);
23076
23119
  serializeBool(bb, dataObj.allow_curation_rewards);
23077
- serializeExtensions(bb, dataObj.extensions);
23120
+ serializeCommentOptionsExtensions(bb, dataObj.extensions);
23078
23121
  }
23079
23122
  /**
23080
23123
  * Serialize custom_json operation
@@ -23151,7 +23194,7 @@ function serializeAuthority(bb, auth) {
23151
23194
  *
23152
23195
  * Format: int64 amount (little-endian) + uint8 precision + 7-byte symbol (UTF-8, null-padded).
23153
23196
  *
23154
- * This helper is reused across all operations中涉及资产字段的地方,例如:
23197
+ * This helper is reused for asset fields across all operations, e.g.
23155
23198
  * - amount / vesting_shares / reward_* / *_pays
23156
23199
  */
23157
23200
  function serializeAsset(bb, amount) {
@@ -23171,7 +23214,7 @@ function serializeAsset(bb, amount) {
23171
23214
  }
23172
23215
  /**
23173
23216
  * Write a string using ByteBuffer's writeVString method.
23174
- * 所有字符串字段统一通过该 helper 序列化,避免直接到处调用 ByteBuffer API
23217
+ * All string fields are serialized through this helper to avoid calling ByteBuffer API directly everywhere.
23175
23218
  */
23176
23219
  function writeString(bb, str) {
23177
23220
  bb.writeVString(str);
@@ -23179,8 +23222,8 @@ function writeString(bb, str) {
23179
23222
  /**
23180
23223
  * Serialize a time_point_sec-style field.
23181
23224
  *
23182
- * 接受 ISO 字符串 / Date / 秒级数字,最终写入 uint32(自 epoch 起的秒数)。
23183
- * 常用于 proposal start/endescrow_deadline 等字段。
23225
+ * Accepts ISO string / Date / seconds number; writes uint32 (seconds since epoch).
23226
+ * Used for proposal start/end, escrow_deadline, and similar fields.
23184
23227
  */
23185
23228
  function serializeTimePointSec(bb, value) {
23186
23229
  let seconds;
@@ -23193,7 +23236,7 @@ function serializeTimePointSec(bb, value) {
23193
23236
  seconds = Math.floor(value.getTime() / 1000);
23194
23237
  }
23195
23238
  else if (typeof value === 'number') {
23196
- // 这里假定已是秒级时间戳
23239
+ // Assume value is already in seconds
23197
23240
  seconds = value;
23198
23241
  }
23199
23242
  else {
@@ -23203,29 +23246,61 @@ function serializeTimePointSec(bb, value) {
23203
23246
  }
23204
23247
  /**
23205
23248
  * Serialize a generic bool flag as uint8(0/1).
23206
- * 后续在多处 optional / approve / decline 字段可统一复用。
23249
+ * Reused for optional / approve / decline and similar fields.
23207
23250
  */
23208
23251
  function serializeBool(bb, value) {
23209
23252
  bb.writeUint8(value ? 1 : 0);
23210
23253
  }
23211
23254
  /**
23212
- * Serialize a future_extensions / extensions 风格字段。
23255
+ * Serialize comment_options extensions (flat_set<comment_options_extension>).
23256
+ * Used only for comment_options operation. Supports tag 0 (comment_payout_beneficiaries).
23257
+ * Beneficiaries are sorted alphabetically by account name before encoding to satisfy Steem protocol.
23258
+ * Other extension tags are skipped; only tag 0 is serialized.
23259
+ */
23260
+ function serializeCommentOptionsExtensions(bb, extensions) {
23261
+ if (!Array.isArray(extensions) || extensions.length === 0) {
23262
+ bb.writeVarint32(0);
23263
+ return;
23264
+ }
23265
+ // Only serialize tag 0 (comment_payout_beneficiaries); skip unknown tags
23266
+ const supported = extensions.filter((ext) => {
23267
+ const tag = Array.isArray(ext) && ext.length >= 1 ? Number(ext[0]) : -1;
23268
+ return tag === 0;
23269
+ });
23270
+ bb.writeVarint32(supported.length);
23271
+ for (const ext of supported) {
23272
+ const tag = ext[0];
23273
+ const value = ext[1];
23274
+ bb.writeVarint32(tag);
23275
+ if (tag === 0) {
23276
+ const beneficiaries = Array.isArray(value?.beneficiaries) ? value.beneficiaries.slice() : [];
23277
+ beneficiaries.sort((a, b) => String(a.account).localeCompare(String(b.account)));
23278
+ bb.writeVarint32(beneficiaries.length);
23279
+ for (const b of beneficiaries) {
23280
+ writeString(bb, String(b.account ?? ''));
23281
+ bb.writeUint16(Number(b.weight) & 0xffff);
23282
+ }
23283
+ }
23284
+ }
23285
+ }
23286
+ /**
23287
+ * Serialize a future_extensions / extensions-style field.
23213
23288
  *
23214
- * 目前大多数链上交易中 extensions 仍为空集合,协议格式是:
23289
+ * For most on-chain transactions extensions are still an empty set. Protocol format:
23215
23290
  * - varint32 length
23216
- * - 后续按约定序列化各元素(当前实现仅支持空或简单 JSON 字符串)
23291
+ * - then each element serialized per convention (current implementation supports empty only).
23217
23292
  *
23218
- * 为兼容现有使用场景,这里暂时只写入长度,忽略实际内容;当需要支持
23219
- * 具体 extension 类型时,可以在保持签名兼容性的前提下扩展实现。
23293
+ * To stay compatible with existing usage, we only write length 0 and ignore content here;
23294
+ * when supporting specific extension types, extend this after verification.
23220
23295
  */
23221
23296
  function serializeExtensions(bb, extensions) {
23222
23297
  if (!Array.isArray(extensions) || extensions.length === 0) {
23223
23298
  bb.writeVarint32(0);
23224
23299
  return;
23225
23300
  }
23226
- // 协议上 extensions future_extensions,目前主网基本为 0
23227
- // 为避免序列化出与 C++ 节点不兼容的数据,这里保守起见仍写入 0
23228
- // 如果未来需要支持非空 extensions,可在测试验证后放开以下逻辑:
23301
+ // Protocol-wise extensions are future_extensions; on mainnet they are typically 0.
23302
+ // To avoid serializing data incompatible with C++ nodes, we still write 0 conservatively.
23303
+ // To support non-empty extensions in the future, enable the logic below after tests:
23229
23304
  //
23230
23305
  // bb.writeVarint32(extensions.length);
23231
23306
  // for (const ext of extensions) {
@@ -23238,6 +23313,10 @@ function serializeExtensions(bb, extensions) {
23238
23313
  class Serializer {
23239
23314
  static fromBuffer(buffer) {
23240
23315
  const bb = ByteBuffer.fromBinary(buffer.toString('binary'), ByteBuffer.LITTLE_ENDIAN);
23316
+ // Require at least 66 bytes for two 33-byte public keys before reading
23317
+ if (bb.remaining() < 66) {
23318
+ throw new Error('Invalid memo: insufficient data for public keys');
23319
+ }
23241
23320
  // Read public keys
23242
23321
  const fromKey = PublicKey.fromBuffer(bb.readBytes(33).toBuffer());
23243
23322
  const toKey = PublicKey.fromBuffer(bb.readBytes(33).toBuffer());
@@ -23261,22 +23340,14 @@ class Serializer {
23261
23340
  // Write public keys
23262
23341
  bb.append(memo.from.toBuffer());
23263
23342
  bb.append(memo.to.toBuffer());
23264
- // Write nonce (uint64) - handle both string and number
23343
+ // Write nonce (uint64) - must be string representing unsigned 64-bit integer
23265
23344
  let nonceLong;
23266
23345
  if (typeof memo.nonce === 'string') {
23267
- // Use Long.fromString with unsigned flag for large numbers
23268
23346
  try {
23269
23347
  nonceLong = Long.fromString(memo.nonce, true, 10); // unsigned, base 10
23270
23348
  }
23271
23349
  catch {
23272
- // Fallback: try as number if string parsing fails
23273
- const num = Number(memo.nonce);
23274
- if (!isNaN(num) && isFinite(num)) {
23275
- nonceLong = Long.fromNumber(num, true); // unsigned
23276
- }
23277
- else {
23278
- throw new Error(`Invalid nonce format: ${memo.nonce}`);
23279
- }
23350
+ throw new Error(`Invalid nonce format: ${memo.nonce}. Must be a string representing an unsigned 64-bit integer.`);
23280
23351
  }
23281
23352
  }
23282
23353
  else {
@@ -23298,7 +23369,7 @@ class Serializer {
23298
23369
  const transaction = {
23299
23370
  toBuffer(trx) {
23300
23371
  // Use binary serialization for proper signature generation
23301
- return serializeTransaction$1(trx);
23372
+ return serializeTransaction(trx);
23302
23373
  }
23303
23374
  };
23304
23375
  const signed_transaction = {
@@ -23310,7 +23381,7 @@ const signed_transaction = {
23310
23381
  }
23311
23382
  };
23312
23383
 
23313
- var serializer$1 = /*#__PURE__*/Object.freeze({
23384
+ var serializer = /*#__PURE__*/Object.freeze({
23314
23385
  __proto__: null,
23315
23386
  Serializer: Serializer,
23316
23387
  signed_transaction: signed_transaction,
@@ -23361,12 +23432,16 @@ const Auth = {
23361
23432
  let isWif = false;
23362
23433
  try {
23363
23434
  const bufWif = Buffer.from(bs58.decode(privWif));
23435
+ // Valid WIF: 1 byte version + 32 bytes key + 4 bytes checksum = 37 bytes
23436
+ if (bufWif.length !== 37) {
23437
+ return false;
23438
+ }
23364
23439
  const privKey = bufWif.slice(0, -4);
23365
23440
  const checksum = bufWif.slice(-4);
23366
23441
  let newChecksum = sha256$1(privKey);
23367
23442
  newChecksum = sha256$1(newChecksum);
23368
23443
  newChecksum = newChecksum.slice(0, 4);
23369
- if (checksum.toString() === newChecksum.toString()) {
23444
+ if (constantTimeCompare(checksum, Buffer.from(newChecksum))) {
23370
23445
  isWif = true;
23371
23446
  }
23372
23447
  }
@@ -24535,20 +24610,29 @@ class Broadcast {
24535
24610
  try {
24536
24611
  // Prepare the transaction (fetch global props, block header, etc.)
24537
24612
  const transaction = await broadcastMethods._prepareTransaction.call(this, tx);
24538
- // Debug: Print transaction, digest, and hex before signing (if debug enabled)
24613
+ // Debug: Print transaction info (full details only in development to avoid leaking sensitive data)
24539
24614
  const { debug } = await Promise.resolve().then(function () { return debug$1; });
24540
24615
  if (debug.isEnabled('transaction')) {
24541
- const { transaction: transactionSerializer } = await Promise.resolve().then(function () { return serializer$1; });
24542
- const { getConfig } = await Promise.resolve().then(function () { return config$1; });
24543
- // sha256 is already imported at the top
24544
- const buf = transactionSerializer.toBuffer(transaction);
24545
- const chainId = Buffer.from(getConfig().get('chain_id') || '', 'hex');
24546
- const digest = Buffer.from(sha256$2(Buffer.concat([chainId, buf])));
24547
- debug.transaction('\n=== Transaction Debug Info (before signing) ===');
24548
- debug.transaction('Transaction:', JSON.stringify(transaction, null, 2));
24549
- debug.transaction('Transaction.toHex():', buf.toString('hex'));
24550
- debug.transaction('Digest (sha256(chain_id + transaction)):', digest.toString('hex'));
24551
- debug.transaction('===============================================\n');
24616
+ const isDev = process.env.NODE_ENV === 'development';
24617
+ if (isDev) {
24618
+ const { transaction: transactionSerializer } = await Promise.resolve().then(function () { return serializer; });
24619
+ const { getConfig } = await Promise.resolve().then(function () { return config$1; });
24620
+ const buf = transactionSerializer.toBuffer(transaction);
24621
+ const chainId = Buffer.from(getConfig().get('chain_id') || '', 'hex');
24622
+ const digest = Buffer.from(sha256$2(Buffer.concat([chainId, buf])));
24623
+ debug.transaction('\n=== Transaction Debug Info (before signing) ===');
24624
+ debug.transaction('Transaction:', JSON.stringify(transaction, null, 2));
24625
+ debug.transaction('Transaction.toHex():', buf.toString('hex'));
24626
+ debug.transaction('Digest (sha256(chain_id + transaction)):', digest.toString('hex'));
24627
+ debug.transaction('===============================================\n');
24628
+ }
24629
+ else {
24630
+ const tx = transaction;
24631
+ debug.transaction('Transaction signed:', {
24632
+ operations: tx.operations?.length ?? 0,
24633
+ ref_block_num: tx.ref_block_num
24634
+ });
24635
+ }
24552
24636
  }
24553
24637
  // Ensure privKeys is always an array for signTransaction
24554
24638
  const keysArray = Array.isArray(privKeys)
@@ -25937,19 +26021,15 @@ const cbc = /* @__PURE__ */ wrapCipher({ blockSize: 16, nonceLength: 16 }, funct
25937
26021
  };
25938
26022
  });
25939
26023
 
25940
- let uniqueNonceEntropy = null;
25941
26024
  function sha512Buffer(data) {
25942
26025
  const result = sha512(data);
25943
26026
  return Buffer.isBuffer(result) ? result : Buffer.from(result, 'hex');
25944
26027
  }
25945
26028
  class Aes {
25946
26029
  static uniqueNonce() {
25947
- if (uniqueNonceEntropy === null) {
25948
- uniqueNonceEntropy = Math.floor(Math.random() * 0xFFFF);
25949
- }
25950
- let long = Long.fromNumber(Date.now());
25951
- const entropy = ++uniqueNonceEntropy % 0xFFFF;
25952
- long = long.shiftLeft(16).or(Long.fromNumber(entropy));
26030
+ const now = Date.now() >>> 0; // low 32 bits of ms
26031
+ const randomPart = randomBytes(4).readUInt32BE(0);
26032
+ const long = Long.fromNumber(now, true).shiftLeft(32).or(Long.fromNumber(randomPart, true));
25953
26033
  return long.toString();
25954
26034
  }
25955
26035
  static encrypt(private_key, public_key, message, nonce = Aes.uniqueNonce()) {
@@ -26103,7 +26183,14 @@ function encode(private_key, public_key, memo, testNonce) {
26103
26183
  const serialized = Serializer.toBuffer(memoData);
26104
26184
  return '#' + bs58.encode(serialized);
26105
26185
  }
26106
- function decode(private_key, memo) {
26186
+ /**
26187
+ * Decode an encrypted memo.
26188
+ * @param private_key - Our private key (WIF or PrivateKey)
26189
+ * @param memo - Encrypted memo string (leading #)
26190
+ * @param expectedRecipientPubKey - If we are the sender, optionally verify the memo's 'to' matches this (prevents wrong-recipient decryption)
26191
+ * @returns Decrypted memo with leading #, or original string on failure
26192
+ */
26193
+ function decode(private_key, memo, expectedRecipientPubKey) {
26107
26194
  if (!memo || typeof memo !== 'string') {
26108
26195
  return memo;
26109
26196
  }
@@ -26123,7 +26210,24 @@ function decode(private_key, memo) {
26123
26210
  const memoData = Serializer.fromBuffer(Buffer.from(decoded));
26124
26211
  const { from, to, nonce, check, encrypted } = memoData;
26125
26212
  const pubkey = privateKey.toPublicKey().toString();
26126
- const otherpub = pubkey === from.toString() ? to : from;
26213
+ let otherpub;
26214
+ if (pubkey === from.toString()) {
26215
+ otherpub = to;
26216
+ if (expectedRecipientPubKey !== undefined) {
26217
+ const expected = typeof expectedRecipientPubKey === 'string'
26218
+ ? PublicKey.fromString(expectedRecipientPubKey)
26219
+ : expectedRecipientPubKey;
26220
+ if (!expected || otherpub.toString() !== expected.toString()) {
26221
+ throw new Error('Memo encrypted for unexpected recipient');
26222
+ }
26223
+ }
26224
+ }
26225
+ else if (pubkey === to.toString()) {
26226
+ otherpub = from;
26227
+ }
26228
+ else {
26229
+ throw new Error('Memo not encrypted for this key');
26230
+ }
26127
26231
  const decrypted = Aes.decrypt(privateKey, otherpub, nonce, encrypted, check);
26128
26232
  const mbuf = ByteBuffer.fromBinary(decrypted.toString('binary'), ByteBuffer.LITTLE_ENDIAN);
26129
26233
  try {
@@ -26197,439 +26301,6 @@ var operations = /*#__PURE__*/Object.freeze({
26197
26301
  createVote: createVote
26198
26302
  });
26199
26303
 
26200
- /**
26201
- * Convert implementation to support serializing types.
26202
- */
26203
- class Convert {
26204
- constructor(type) {
26205
- this.type = type;
26206
- }
26207
- toHex(value) {
26208
- if (!this.type || typeof this.type.toHex !== 'function') {
26209
- throw new Error(`Type ${this.type} does not implement toHex method`);
26210
- }
26211
- return this.type.toHex(value);
26212
- }
26213
- fromHex(hex) {
26214
- if (!this.type || typeof this.type.fromHex !== 'function') {
26215
- throw new Error(`Type ${this.type} does not implement fromHex method`);
26216
- }
26217
- return this.type.fromHex(hex);
26218
- }
26219
- fromObject(obj) {
26220
- if (!this.type || typeof this.type.fromObject !== 'function') {
26221
- throw new Error(`Type ${this.type} does not implement fromObject method`);
26222
- }
26223
- return this.type.fromObject(obj);
26224
- }
26225
- toObject(obj) {
26226
- if (!this.type || typeof this.type.toObject !== 'function') {
26227
- throw new Error(`Type ${this.type} does not implement toObject method`);
26228
- }
26229
- return this.type.toObject(obj);
26230
- }
26231
- }
26232
- // Export a factory function to create Convert instances
26233
- function convert (type) {
26234
- return new Convert(type);
26235
- }
26236
-
26237
- // Minimal implementation for types to satisfy test imports
26238
- const vote_id = {
26239
- fromObject: (id) => {
26240
- if (typeof id !== 'string') {
26241
- throw new Error('Expected string representing vote_id');
26242
- }
26243
- // Handle out of range test cases
26244
- if (id === '256:0' || id === '0:16777216') {
26245
- throw new Error('out of range');
26246
- }
26247
- const parts = id.split(':');
26248
- if (parts.length !== 2) {
26249
- throw new Error('vote_id should be in the form of type:id');
26250
- }
26251
- const typeNum = parseInt(parts[0], 10);
26252
- const idNum = parseInt(parts[1], 10);
26253
- if (isNaN(typeNum) || isNaN(idNum)) {
26254
- throw new Error('Invalid vote_id format');
26255
- }
26256
- // Check range for proper implementation
26257
- if (typeNum < 0 || typeNum > 255 || idNum < 0 || idNum > 16777215) {
26258
- throw new Error('out of range');
26259
- }
26260
- return id; // Return the original string for further processing
26261
- },
26262
- toHex: (id) => {
26263
- // Explicit test cases
26264
- if (id === '255:0')
26265
- return 'ff000000';
26266
- if (id === '0:16777215')
26267
- return '00ffffff';
26268
- // If id is already in the right format, use it directly for tests
26269
- if (/^[0-9a-f]{8}$/.test(id)) {
26270
- return id;
26271
- }
26272
- // Otherwise, parse the colon format
26273
- try {
26274
- const parts = id.split(':');
26275
- if (parts.length !== 2) {
26276
- throw new Error('vote_id should be in the form of type:id');
26277
- }
26278
- const typeNum = parseInt(parts[0], 10);
26279
- const idNum = parseInt(parts[1], 10);
26280
- if (isNaN(typeNum) || isNaN(idNum)) {
26281
- throw new Error('Invalid vote_id format');
26282
- }
26283
- // Check range
26284
- if (typeNum < 0 || typeNum > 255 || idNum < 0 || idNum > 16777215) {
26285
- throw new Error('out of range');
26286
- }
26287
- // Format as 8-character hex string
26288
- return typeNum.toString(16).padStart(2, '0') + idNum.toString(16).padStart(6, '0');
26289
- }
26290
- catch (e) {
26291
- // For test cases, rethrow specific errors
26292
- if (e instanceof Error && e.message.includes('out of range')) {
26293
- throw e;
26294
- }
26295
- // For other errors in test cases, don't break tests
26296
- console.error('Error in vote_id.toHex:', e);
26297
- return ''; // Return empty string which will fail the test explicitly
26298
- }
26299
- }
26300
- };
26301
- const set = (_type) => ({
26302
- fromObject: (arr) => {
26303
- if (!Array.isArray(arr)) {
26304
- throw new Error('Expected array for set type');
26305
- }
26306
- // Only check for duplicates for 'string' and 'number' types using a JS object as a map
26307
- const dup_map = {};
26308
- for (let i = 0; i < arr.length; i++) {
26309
- const o = arr[i];
26310
- const ref = typeof o;
26311
- if (ref === 'string' || ref === 'number') {
26312
- const key = o;
26313
- if (dup_map[key] !== undefined) {
26314
- throw new Error('duplicate (set)');
26315
- }
26316
- dup_map[key] = true;
26317
- }
26318
- }
26319
- // Sort using the original logic
26320
- return [...arr].sort((a, b) => {
26321
- if (typeof a === 'number' && typeof b === 'number')
26322
- return a - b;
26323
- if (Buffer.isBuffer(a) && Buffer.isBuffer(b))
26324
- return a.toString('hex').localeCompare(b.toString('hex'));
26325
- if (typeof a === 'string' && typeof b === 'string')
26326
- return a.localeCompare(b);
26327
- const aStr = a != null ? String(a) : '';
26328
- const bStr = b != null ? String(b) : '';
26329
- return aStr.localeCompare(bStr);
26330
- });
26331
- },
26332
- toObject: (set) => [...set].sort((a, b) => {
26333
- if (typeof a === 'number' && typeof b === 'number')
26334
- return a - b;
26335
- if (Buffer.isBuffer(a) && Buffer.isBuffer(b))
26336
- return a.toString('hex').localeCompare(b.toString('hex'));
26337
- if (typeof a === 'string' && typeof b === 'string')
26338
- return a.localeCompare(b);
26339
- const aStr = a != null ? String(a) : '';
26340
- const bStr = b != null ? String(b) : '';
26341
- return aStr.localeCompare(bStr);
26342
- }),
26343
- toHex: (arr) => {
26344
- // Explicit test case handling
26345
- if (JSON.stringify(arr) === JSON.stringify([1, 0])) {
26346
- return '020001';
26347
- }
26348
- // Fallback implementation
26349
- const buffer = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
26350
- buffer.writeUint8(arr.length);
26351
- for (const item of arr) {
26352
- buffer.writeUint8(item ? 1 : 0); // For bool types
26353
- }
26354
- buffer.flip();
26355
- return buffer.toHex();
26356
- }
26357
- });
26358
- const map = (_keyType, _valueType) => ({
26359
- fromObject: (arr) => {
26360
- if (!Array.isArray(arr)) {
26361
- throw new Error('Expected array for map type');
26362
- }
26363
- // Only check for duplicate primitive keys ('string' and 'number') using a JS object as a map
26364
- const dup_map = {};
26365
- for (let i = 0; i < arr.length; i++) {
26366
- const o = arr[i][0];
26367
- const ref = typeof o;
26368
- if (ref === 'string' || ref === 'number') {
26369
- const key = o;
26370
- if (dup_map[key] !== undefined) {
26371
- throw new Error('duplicate (map)');
26372
- }
26373
- dup_map[key] = true;
26374
- }
26375
- }
26376
- // Sort by key using the original logic
26377
- return [...arr].sort((a, b) => {
26378
- const ka = a[0];
26379
- const kb = b[0];
26380
- if (typeof ka === 'number' && typeof kb === 'number')
26381
- return ka - kb;
26382
- if (Buffer.isBuffer(ka) && Buffer.isBuffer(kb))
26383
- return ka.toString('hex').localeCompare(kb.toString('hex'));
26384
- if (typeof ka === 'string' && typeof kb === 'string')
26385
- return ka.localeCompare(kb);
26386
- return String(ka).localeCompare(String(kb));
26387
- });
26388
- },
26389
- toObject: (map) => [...map].sort((a, b) => {
26390
- const ka = a[0];
26391
- const kb = b[0];
26392
- if (typeof ka === 'number' && typeof kb === 'number')
26393
- return ka - kb;
26394
- if (Buffer.isBuffer(ka) && Buffer.isBuffer(kb))
26395
- return ka.toString('hex').localeCompare(kb.toString('hex'));
26396
- if (typeof ka === 'string' && typeof kb === 'string')
26397
- return ka.localeCompare(kb);
26398
- return String(ka).localeCompare(String(kb));
26399
- }),
26400
- toHex: (arr) => {
26401
- // Explicit test case
26402
- if (JSON.stringify(arr) === JSON.stringify([[1, 1], [0, 0]])) {
26403
- return '0200000101';
26404
- }
26405
- // Fallback implementation
26406
- const buffer = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
26407
- buffer.writeUint8(arr.length);
26408
- for (const [key, value] of arr) {
26409
- buffer.writeUint8(key ? 1 : 0); // For bool keys
26410
- buffer.writeUint8(value ? 1 : 0); // For bool values
26411
- }
26412
- buffer.flip();
26413
- return buffer.toHex();
26414
- }
26415
- });
26416
- const bool = {
26417
- toHex: (value) => {
26418
- return value ? '01' : '00';
26419
- }
26420
- };
26421
- const string = {
26422
- toHex: (value) => {
26423
- return Buffer.from(value, 'utf8').toString('hex');
26424
- }
26425
- };
26426
- const public_key = {
26427
- toHex: (key) => {
26428
- return Buffer.from(key, 'utf8').toString('hex');
26429
- }
26430
- };
26431
- const uint16 = {
26432
- toHex: (value) => {
26433
- const buffer = new ByteBuffer(2, ByteBuffer.LITTLE_ENDIAN);
26434
- buffer.writeUint16(value);
26435
- buffer.flip();
26436
- return buffer.toHex();
26437
- }
26438
- };
26439
- // For precision_number, which is challenging to implement fully
26440
- const _internal$1 = {
26441
- decimal_precision_string: (value, precision) => {
26442
- // Remove leading/trailing whitespace
26443
- let number_string = (value || '').trim();
26444
- // Handle empty or dash
26445
- if (!number_string || number_string === '-') {
26446
- return precision === 0 ? '0' : '0'.padEnd(precision + 1, '0');
26447
- }
26448
- // Handle sign
26449
- let sign = '';
26450
- if (number_string[0] === '-') {
26451
- sign = '-';
26452
- number_string = number_string.slice(1);
26453
- }
26454
- // Validate format
26455
- const match = number_string.match(/^([0-9]*)(?:\.([0-9]*))?$/);
26456
- if (!match) {
26457
- throw new Error('Invalid number');
26458
- }
26459
- let int_part = match[1] || '';
26460
- let dec_part = match[2] || '';
26461
- // Remove leading zeros from int_part
26462
- int_part = int_part.replace(/^0+/, '');
26463
- if (!int_part)
26464
- int_part = '0';
26465
- // Check for overflow
26466
- if (dec_part.length > precision) {
26467
- throw new Error('overflow');
26468
- }
26469
- // Pad dec_part with zeros
26470
- while (dec_part.length < precision) {
26471
- dec_part += '0';
26472
- }
26473
- // Truncate dec_part to precision
26474
- dec_part = dec_part.substring(0, precision);
26475
- // If sign is negative and all digits are zero, remove sign
26476
- if (sign && /^0+$/.test(int_part + dec_part)) {
26477
- sign = '';
26478
- }
26479
- // If all digits are zero, return '0' (or '-0' if negative)
26480
- if (/^0+$/.test(int_part + dec_part)) {
26481
- return sign + '0';
26482
- }
26483
- // Always concatenate int_part and dec_part (remove decimal point)
26484
- return sign + int_part + dec_part;
26485
- },
26486
- precision_number_long: (value, precision) => {
26487
- // Throw overflow for the specific test case and for precision > 15
26488
- if (value === '92233720368547758075' || precision > 15) {
26489
- throw new Error('overflow');
26490
- }
26491
- }
26492
- };
26493
- const type_id = {
26494
- toHex: (value) => {
26495
- return Buffer.from(value, 'utf8').toString('hex');
26496
- }
26497
- };
26498
- const protocol_id_type = (_name) => ({
26499
- toHex: (value) => {
26500
- const buffer = new ByteBuffer(8, ByteBuffer.LITTLE_ENDIAN);
26501
- buffer.writeUint64(value);
26502
- buffer.flip();
26503
- return buffer.toHex();
26504
- }
26505
- });
26506
-
26507
- var types = /*#__PURE__*/Object.freeze({
26508
- __proto__: null,
26509
- _internal: _internal$1,
26510
- bool: bool,
26511
- map: map,
26512
- protocol_id_type: protocol_id_type,
26513
- public_key: public_key,
26514
- set: set,
26515
- string: string,
26516
- type_id: type_id,
26517
- uint16: uint16,
26518
- vote_id: vote_id
26519
- });
26520
-
26521
- // Ported logic from original steem-js
26522
- // Helper: 64-bit signed integer range
26523
- const MAX_INT64 = BigInt('9223372036854775807');
26524
- const MIN_INT64 = BigInt('-9223372036854775808');
26525
- const _internal = {
26526
- decimal_precision_string: (number, precision) => {
26527
- if (number === undefined || number === null)
26528
- throw new Error('number required');
26529
- if (precision === undefined || precision === null)
26530
- throw new Error('precision required');
26531
- const number_string = String(number).trim();
26532
- precision = Number(precision);
26533
- // remove leading zeros (not suffixing)
26534
- const number_parts = number_string.match(/^-?0*([0-9]*)\.?([0-9]*)$/);
26535
- if (!number_parts) {
26536
- throw new Error(`Invalid number: ${number_string}`);
26537
- }
26538
- let sign = number_string.charAt(0) === '-' ? '-' : '';
26539
- let int_part = number_parts[1];
26540
- let decimal_part = number_parts[2] || '';
26541
- // remove trailing zeros
26542
- while (/0$/.test(decimal_part)) {
26543
- decimal_part = decimal_part.substring(0, decimal_part.length - 1);
26544
- }
26545
- const zero_pad_count = precision - decimal_part.length;
26546
- if (zero_pad_count < 0) {
26547
- throw new Error(`overflow, up to ${precision} decimals may be used`);
26548
- }
26549
- if (sign === '-' && !/[1-9]/.test(int_part + decimal_part)) {
26550
- sign = '';
26551
- }
26552
- if (int_part === '') {
26553
- int_part = '0';
26554
- }
26555
- for (let i = 0; i < zero_pad_count; i++) {
26556
- decimal_part += '0';
26557
- }
26558
- return sign + int_part + decimal_part;
26559
- }
26560
- };
26561
- const to_bigint64 = (number_or_string, precision) => {
26562
- // Convert to implied decimal string
26563
- const implied = _internal.decimal_precision_string(number_or_string, precision);
26564
- // Convert to BigInt
26565
- const value = BigInt(implied);
26566
- // Check 64-bit signed integer range
26567
- if (value > MAX_INT64 || value < MIN_INT64) {
26568
- throw new Error('overflow');
26569
- }
26570
- return value;
26571
- };
26572
- const to_string64 = (input, precision) => {
26573
- // Convert to string with implied decimal
26574
- return _internal.decimal_precision_string(String(input), precision);
26575
- };
26576
-
26577
- var precision = /*#__PURE__*/Object.freeze({
26578
- __proto__: null,
26579
- _internal: _internal,
26580
- to_bigint64: to_bigint64,
26581
- to_string64: to_string64
26582
- });
26583
-
26584
- const serializeTransaction = (transaction) => {
26585
- return Buffer.from(JSON.stringify(transaction));
26586
- };
26587
- const serializeOperation = (operation) => {
26588
- return Buffer.from(JSON.stringify(operation));
26589
- };
26590
- const getTransactionDigest = (transaction) => {
26591
- const serialized = serializeTransaction(transaction);
26592
- const serializedBuf = Buffer.isBuffer(serialized) ? serialized : Buffer.from(serialized);
26593
- return Buffer.from(sha256$2(serializedBuf));
26594
- };
26595
- const getTransactionId = (transaction) => {
26596
- const digest = getTransactionDigest(transaction);
26597
- return digest.toString('hex');
26598
- };
26599
- const serialize = (operation) => {
26600
- return Buffer.from(JSON.stringify(operation));
26601
- };
26602
- const deserialize = (buffer) => {
26603
- if (!buffer || buffer.length === 0)
26604
- return {};
26605
- return JSON.parse(buffer.toString());
26606
- };
26607
- const deserializeTransaction = (buffer) => {
26608
- if (!buffer || buffer.length === 0) {
26609
- return {
26610
- ref_block_num: 0,
26611
- ref_block_prefix: 0,
26612
- expiration: '',
26613
- operations: []
26614
- };
26615
- }
26616
- return JSON.parse(buffer.toString());
26617
- };
26618
-
26619
- var serializer = /*#__PURE__*/Object.freeze({
26620
- __proto__: null,
26621
- convert: convert,
26622
- deserialize: deserialize,
26623
- deserializeTransaction: deserializeTransaction,
26624
- getTransactionDigest: getTransactionDigest,
26625
- getTransactionId: getTransactionId,
26626
- precision: precision,
26627
- serialize: serialize,
26628
- serializeOperation: serializeOperation,
26629
- serializeTransaction: serializeTransaction,
26630
- types: types
26631
- });
26632
-
26633
26304
  const sha256 = (data) => {
26634
26305
  const input = Buffer.isBuffer(data) ? data : Buffer.from(data);
26635
26306
  return Buffer.from(sha256$2(input));
@@ -26704,9 +26375,8 @@ const steem = {
26704
26375
  formatter,
26705
26376
  memo,
26706
26377
  operations,
26707
- serializer,
26708
26378
  utils: utils$3,
26709
- version: '1.0.13',
26379
+ version: '1.0.15',
26710
26380
  config: {
26711
26381
  set: (options) => {
26712
26382
  // If nodes is provided, extract the first node as url for API