@steemit/steem-js 1.0.12 → 1.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.umd.js CHANGED
@@ -16593,6 +16593,20 @@
16593
16593
  const secp256k1$1 = new elliptic.ec('secp256k1');
16594
16594
  const G = secp256k1$1.g;
16595
16595
  const n = new BN(secp256k1$1.n.toString());
16596
+ /**
16597
+ * Constant-time buffer comparison to prevent timing attacks.
16598
+ * Returns true only if a.length === b.length and a[i] === b[i] for all i.
16599
+ */
16600
+ function constantTimeCompare(a, b) {
16601
+ if (a.length !== b.length) {
16602
+ return false;
16603
+ }
16604
+ let result = 0;
16605
+ for (let i = 0; i < a.length; i++) {
16606
+ result |= a[i] ^ b[i];
16607
+ }
16608
+ return result === 0;
16609
+ }
16596
16610
  class PrivateKey {
16597
16611
  /**
16598
16612
  * @private see static functions
@@ -16605,11 +16619,8 @@
16605
16619
  if (!buffer.Buffer.isBuffer(buf)) {
16606
16620
  throw new Error("Expecting parameter to be a Buffer type");
16607
16621
  }
16608
- if (32 !== buf.length) {
16609
- debug.warn(`WARN: Expecting 32 bytes, instead got ${buf.length}, stack trace:`, new Error().stack);
16610
- }
16611
- if (buf.length === 0) {
16612
- throw new Error("Empty buffer");
16622
+ if (buf.length !== 32) {
16623
+ throw new Error(`Invalid private key buffer: expected 32 bytes, got ${buf.length}`);
16613
16624
  }
16614
16625
  return new PrivateKey(new BN(buf));
16615
16626
  }
@@ -16634,21 +16645,33 @@
16634
16645
  * @return {string} Wallet Import Format (still a secret, Not encrypted)
16635
16646
  */
16636
16647
  static fromWif(private_wif) {
16637
- const private_wif_buffer = buffer.Buffer.from(bs58.decode(private_wif));
16648
+ if (!private_wif || typeof private_wif !== 'string') {
16649
+ throw new Error('Invalid WIF: empty or not a string');
16650
+ }
16651
+ let private_wif_buffer;
16652
+ try {
16653
+ private_wif_buffer = buffer.Buffer.from(bs58.decode(private_wif));
16654
+ }
16655
+ catch {
16656
+ throw new Error('Invalid WIF: failed to decode base58');
16657
+ }
16658
+ // Valid WIF: 1 byte version + 32 bytes key + 4 bytes checksum = 37 bytes
16659
+ if (private_wif_buffer.length !== 37) {
16660
+ throw new Error(`Invalid WIF: expected 37 bytes, got ${private_wif_buffer.length}`);
16661
+ }
16638
16662
  const version = private_wif_buffer.readUInt8(0);
16639
- if (version !== 0x80)
16640
- throw new Error(`Expected version ${0x80}, instead got ${version}`);
16641
- // checksum includes the version
16642
- const private_key = private_wif_buffer.slice(0, -4);
16643
- const checksum = private_wif_buffer.slice(-4);
16644
- let new_checksum = sha256$1(private_key);
16663
+ if (version !== 0x80) {
16664
+ throw new Error(`Invalid WIF: expected version 0x80, got 0x${version.toString(16)}`);
16665
+ }
16666
+ const private_key = private_wif_buffer.slice(1, 33);
16667
+ const checksum = private_wif_buffer.slice(33);
16668
+ let new_checksum = sha256$1(buffer.Buffer.concat([buffer.Buffer.from([0x80]), private_key]));
16645
16669
  new_checksum = sha256$1(new_checksum);
16646
16670
  new_checksum = new_checksum.slice(0, 4);
16647
- if (checksum.toString() !== new_checksum.toString()) {
16671
+ if (!constantTimeCompare(checksum, buffer.Buffer.from(new_checksum))) {
16648
16672
  throw new Error('Invalid WIF key (checksum miss-match)');
16649
16673
  }
16650
- private_key.writeUInt8(0x80, 0);
16651
- return PrivateKey.fromBuffer(private_key.slice(1));
16674
+ return PrivateKey.fromBuffer(private_key);
16652
16675
  }
16653
16676
  toWif() {
16654
16677
  const private_key = this.toBuffer();
@@ -17027,18 +17050,21 @@
17027
17050
  }
17028
17051
  catch (error) {
17029
17052
  // try next value
17030
- console.debug(`Recovery attempt ${i} failed:`, error.message);
17053
+ if (process$1.env.NODE_ENV === 'development') {
17054
+ console.debug(`Recovery attempt ${i} failed:`, error.message);
17055
+ }
17031
17056
  }
17032
17057
  }
17033
- // Additional debugging
17034
- console.debug('All recovery attempts failed. Signature:', {
17035
- r: signature.r.toString(16),
17036
- s: signature.s.toString(16)
17037
- });
17038
- console.debug('Expected public key:', {
17039
- x: Q.getX().toString(16),
17040
- y: Q.getY().toString(16)
17041
- });
17058
+ if (process$1.env.NODE_ENV === 'development') {
17059
+ console.debug('All recovery attempts failed. Signature:', {
17060
+ r: signature.r.toString(16),
17061
+ s: signature.s.toString(16)
17062
+ });
17063
+ console.debug('Expected public key:', {
17064
+ x: Q.getX().toString(16),
17065
+ y: Q.getY().toString(16)
17066
+ });
17067
+ }
17042
17068
  throw new Error('Unable to find valid recovery factor');
17043
17069
  }
17044
17070
 
@@ -17090,9 +17116,10 @@
17090
17116
  const d = privKey.d;
17091
17117
  let ecsignature;
17092
17118
  let nonce = 0;
17119
+ const MAX_NONCE_ATTEMPTS = 1000;
17093
17120
  // Match old-steem-js behavior: find canonical signature (lenR === 32 && lenS === 32)
17094
17121
  // Based on C++ is_fc_canonical logic
17095
- while (true) {
17122
+ while (nonce < MAX_NONCE_ATTEMPTS) {
17096
17123
  ecsignature = sign$3(secp256k1, buf_sha256, d, nonce++);
17097
17124
  const rBa = ecsignature.r.toArrayLike(buffer.Buffer, 'be', 32);
17098
17125
  const sBa = ecsignature.s.toArrayLike(buffer.Buffer, 'be', 32);
@@ -17109,6 +17136,9 @@
17109
17136
  console.debug("WARN: " + nonce + " attempts to find canonical signature");
17110
17137
  }
17111
17138
  }
17139
+ if (nonce >= MAX_NONCE_ATTEMPTS || ecsignature === undefined) {
17140
+ throw new Error('Failed to find canonical signature after maximum attempts');
17141
+ }
17112
17142
  const i = calcPubKeyRecoveryParam(secp256k1, new BN(buf_sha256), ecsignature, privKey.toPublic().Q);
17113
17143
  // Use recovery byte 31-34 (instead of 27-30) to be compatible with dsteem
17114
17144
  // dsteem expects: recovery = byte - 31, so byte = recovery + 31
@@ -17409,7 +17439,11 @@
17409
17439
  if (Number.isNaN(timestamp)) {
17410
17440
  throw new Error('Invalid timestamp');
17411
17441
  }
17412
- if (Date.now() - timestamp > 60 * 1000) {
17442
+ const now = Date.now();
17443
+ const timeDiff = Math.abs(now - timestamp);
17444
+ const SIGNATURE_VALIDITY_MS = 60 * 1000;
17445
+ const MAX_CLOCK_SKEW_MS = 5 * 60 * 1000;
17446
+ if (timeDiff > SIGNATURE_VALIDITY_MS + MAX_CLOCK_SKEW_MS) {
17413
17447
  throw new Error('Signature expired');
17414
17448
  }
17415
17449
  const message = hashMessage(signed.timestamp, signed.account, request.method, signed.params, nonce);
@@ -18359,7 +18393,37 @@
18359
18393
  }
18360
18394
  }
18361
18395
 
18362
- // @ts-expect-error: No types for 'retry'
18396
+ /** Detect Node.js for optional undici Agent (custom TLS). */
18397
+ const isNode = typeof process$1 !== 'undefined' &&
18398
+ typeof process$1.versions === 'object' &&
18399
+ typeof process$1.versions.node === 'string';
18400
+ /**
18401
+ * Build RequestInit for fetch. In Node when options.httpsOptions is set, inject undici Agent as dispatcher.
18402
+ */
18403
+ async function buildFetchOptions(body, options) {
18404
+ const init = {
18405
+ method: 'POST',
18406
+ headers: {
18407
+ 'Content-Type': 'application/json',
18408
+ 'Accept': 'application/json'
18409
+ },
18410
+ body
18411
+ };
18412
+ if (isNode && options.httpsOptions) {
18413
+ // Node 18+ built-in fetch uses undici; custom TLS via node:undici Agent (built-in, no package)
18414
+ // @ts-expect-error - node:undici is Node built-in, not in @types/node
18415
+ const { Agent } = await import('node:undici');
18416
+ const opts = options.httpsOptions;
18417
+ const agent = new Agent({
18418
+ connect: {
18419
+ rejectUnauthorized: opts.rejectUnauthorized,
18420
+ ca: opts.ca
18421
+ }
18422
+ });
18423
+ init.dispatcher = agent;
18424
+ }
18425
+ return init;
18426
+ }
18363
18427
  /**
18364
18428
  * Extended Error type for JSON-RPC errors
18365
18429
  */
@@ -18379,29 +18443,22 @@
18379
18443
  * @param request - The JSON-RPC request object
18380
18444
  * @param fetchMethod - Optional fetch implementation (defaults to global fetch)
18381
18445
  * @param timeoutMs - Request timeout in milliseconds (default: 30000)
18446
+ * @param httpsOptions - Optional TLS options (Node.js only): rejectUnauthorized, ca
18382
18447
  * @returns Promise resolving to the JSON-RPC result
18383
18448
  */
18384
- const jsonRpc = async (url, request, fetchMethod = fetch, timeoutMs = 30000) => {
18449
+ const jsonRpc = async (url, request, fetchMethod = fetch, timeoutMs = 30000, httpsOptions) => {
18385
18450
  const payload = {
18386
18451
  jsonrpc: '2.0',
18387
18452
  ...request
18388
18453
  };
18389
18454
  let timeoutId = null;
18390
- // Create a promise that will reject after the timeout
18391
18455
  const timeoutPromise = new Promise((_, reject) => {
18392
18456
  timeoutId = setTimeout(() => {
18393
18457
  reject(new Error(`Request timeout after ${timeoutMs}ms`));
18394
18458
  }, timeoutMs);
18395
18459
  });
18396
- // Create the fetch promise
18397
- const fetchPromise = fetchMethod(url, {
18398
- method: 'POST',
18399
- headers: {
18400
- 'Content-Type': 'application/json',
18401
- 'Accept': 'application/json'
18402
- },
18403
- body: JSON.stringify(payload)
18404
- })
18460
+ const fetchOptions = await buildFetchOptions(JSON.stringify(payload), { httpsOptions });
18461
+ const fetchPromise = fetchMethod(url, fetchOptions)
18405
18462
  .then(async (res) => {
18406
18463
  if (!res.ok) {
18407
18464
  throw new Error(`HTTP ${res.status}: ${res.statusText}`);
@@ -18452,71 +18509,56 @@
18452
18509
  const params = [api, data.method, data.params];
18453
18510
  const isBroadcast = this.isBroadcastOperation(data.method);
18454
18511
  const retryOptions = this.options.retry;
18455
- // Note: timeout handling is done via AbortController in jsonRpc function
18456
- if (!isBroadcast && retryOptions) {
18457
- const operation = typeof retryOptions === 'object' ? retry$1.operation(retryOptions) : retry$1.operation();
18458
- operation.attempt((currentAttempt) => {
18459
- fetchMethod(url, {
18460
- method: 'POST',
18461
- body: JSON.stringify({
18462
- jsonrpc: '2.0',
18463
- method: 'call',
18464
- params,
18465
- id
18466
- }),
18467
- headers: { 'Content-Type': 'application/json' },
18468
- })
18469
- .then(async (res) => {
18470
- if (!res.ok) {
18471
- throw new Error(`HTTP ${res.status}: ${res.statusText}`);
18472
- }
18473
- return res.json();
18474
- })
18512
+ const body = JSON.stringify({
18513
+ jsonrpc: '2.0',
18514
+ method: 'call',
18515
+ params,
18516
+ id
18517
+ });
18518
+ const doRequest = (fetchOpts) => fetchMethod(url, fetchOpts)
18519
+ .then(async (res) => {
18520
+ if (!res.ok) {
18521
+ throw new Error(`HTTP ${res.status}: ${res.statusText}`);
18522
+ }
18523
+ return res.json();
18524
+ });
18525
+ const runWithOptions = (fetchOpts) => {
18526
+ if (!isBroadcast && retryOptions) {
18527
+ const operation = typeof retryOptions === 'object' ? retry$1.operation(retryOptions) : retry$1.operation();
18528
+ operation.attempt((currentAttempt) => {
18529
+ doRequest(fetchOpts)
18530
+ .then((result) => {
18531
+ if (result.error) {
18532
+ const error = new JsonRpcError(result.error.message || 'JSON-RPC error', result.error.code, result.error.data);
18533
+ callback(error, undefined, currentAttempt);
18534
+ }
18535
+ else {
18536
+ callback(null, result.result, currentAttempt);
18537
+ }
18538
+ }, (error) => {
18539
+ if (operation.retry(error)) {
18540
+ return;
18541
+ }
18542
+ callback(operation.mainError(), undefined, currentAttempt);
18543
+ });
18544
+ });
18545
+ }
18546
+ else {
18547
+ doRequest(fetchOpts)
18475
18548
  .then((result) => {
18476
- // Check for JSON-RPC errors
18477
18549
  if (result.error) {
18478
18550
  const error = new JsonRpcError(result.error.message || 'JSON-RPC error', result.error.code, result.error.data);
18479
- callback(error, undefined, currentAttempt);
18551
+ callback(error, undefined, 1);
18480
18552
  }
18481
18553
  else {
18482
- callback(null, result.result, currentAttempt);
18483
- }
18484
- }, (error) => {
18485
- if (operation.retry(error)) {
18486
- return;
18554
+ callback(null, result.result, 1);
18487
18555
  }
18488
- callback(operation.mainError(), undefined, currentAttempt);
18489
- });
18490
- });
18491
- }
18492
- else {
18493
- fetchMethod(url, {
18494
- method: 'POST',
18495
- body: JSON.stringify({
18496
- jsonrpc: '2.0',
18497
- method: 'call',
18498
- params,
18499
- id
18500
- }),
18501
- headers: { 'Content-Type': 'application/json' }
18502
- })
18503
- .then(async (res) => {
18504
- if (!res.ok) {
18505
- throw new Error(`HTTP ${res.status}: ${res.statusText}`);
18506
- }
18507
- return res.json();
18508
- })
18509
- .then((result) => {
18510
- // Check for JSON-RPC errors
18511
- if (result.error) {
18512
- const error = new JsonRpcError(result.error.message || 'JSON-RPC error', result.error.code, result.error.data);
18513
- callback(error, undefined, 1);
18514
- }
18515
- else {
18516
- callback(null, result.result, 1);
18517
- }
18518
- }, (error) => callback(error instanceof Error ? error : new Error(String(error)), undefined, 1));
18519
- }
18556
+ }, (error) => callback(error instanceof Error ? error : new Error(String(error)), undefined, 1));
18557
+ }
18558
+ };
18559
+ buildFetchOptions(body, this.options)
18560
+ .then(runWithOptions)
18561
+ .catch((err) => callback(err instanceof Error ? err : new Error(String(err)), undefined, 1));
18520
18562
  }
18521
18563
  }
18522
18564
 
@@ -25078,7 +25120,7 @@
25078
25120
  * Serialize a transaction to binary format for Steem blockchain
25079
25121
  * This is a simplified implementation that handles the basic structure
25080
25122
  */
25081
- function serializeTransaction$1(trx) {
25123
+ function serializeTransaction(trx) {
25082
25124
  const bb = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
25083
25125
  const trxObj = trx;
25084
25126
  // Write ref_block_num (uint16)
@@ -25108,7 +25150,7 @@
25108
25150
  const operations = (Array.isArray(trxObj.operations) ? trxObj.operations : []);
25109
25151
  bb.writeVarint32(operations.length);
25110
25152
  for (const op of operations) {
25111
- serializeOperation$1(bb, op);
25153
+ serializeOperation(bb, op);
25112
25154
  }
25113
25155
  // Write extensions (set of future_extensions, which is void/empty)
25114
25156
  bb.writeVarint32(0); // Empty set
@@ -25137,7 +25179,7 @@
25137
25179
  /**
25138
25180
  * Serialize an operation to binary format
25139
25181
  */
25140
- function serializeOperation$1(bb, op) {
25182
+ function serializeOperation(bb, op) {
25141
25183
  if (!Array.isArray(op) || op.length !== 2) {
25142
25184
  throw new Error('Operation must be an array of [operation_type, operation_data]');
25143
25185
  }
@@ -25169,9 +25211,45 @@
25169
25211
  'account_witness_proxy': 13,
25170
25212
  'pow': 14,
25171
25213
  'custom': 15,
25214
+ 'report_over_production': 16,
25172
25215
  'delete_comment': 17,
25173
25216
  'custom_json': 18,
25174
25217
  'comment_options': 19,
25218
+ 'set_withdraw_vesting_route': 20,
25219
+ 'limit_order_create2': 21,
25220
+ 'claim_account': 22,
25221
+ 'create_claimed_account': 23,
25222
+ 'request_account_recovery': 24,
25223
+ 'recover_account': 25,
25224
+ 'change_recovery_account': 26,
25225
+ 'escrow_transfer': 27,
25226
+ 'escrow_dispute': 28,
25227
+ 'escrow_release': 29,
25228
+ 'pow2': 30,
25229
+ 'escrow_approve': 31,
25230
+ 'transfer_to_savings': 32,
25231
+ 'transfer_from_savings': 33,
25232
+ 'cancel_transfer_from_savings': 34,
25233
+ 'custom_binary': 35,
25234
+ 'decline_voting_rights': 36,
25235
+ 'reset_account': 37,
25236
+ 'set_reset_account': 38,
25237
+ 'claim_reward_balance': 39,
25238
+ 'delegate_vesting_shares': 40,
25239
+ 'account_create_with_delegation': 41,
25240
+ 'witness_set_properties': 42,
25241
+ 'account_update2': 43,
25242
+ 'create_proposal': 44,
25243
+ 'update_proposal_votes': 45,
25244
+ 'remove_proposal': 46,
25245
+ 'claim_reward_balance2': 47,
25246
+ 'fill_convert_request': 48,
25247
+ 'comment_reward': 49,
25248
+ 'liquidity_reward': 50,
25249
+ 'interest': 51,
25250
+ 'fill_vesting_withdraw': 52,
25251
+ 'fill_order': 53,
25252
+ 'fill_transfer_from_savings': 54,
25175
25253
  };
25176
25254
  const index = opMap[opType];
25177
25255
  if (index === undefined) {
@@ -25196,6 +25274,135 @@
25196
25274
  case 'account_create':
25197
25275
  serializeAccountCreate(bb, opData);
25198
25276
  break;
25277
+ case 'account_update':
25278
+ serializeAccountUpdate(bb, opData);
25279
+ break;
25280
+ case 'account_create_with_delegation':
25281
+ serializeAccountCreateWithDelegation(bb, opData);
25282
+ break;
25283
+ case 'create_claimed_account':
25284
+ serializeCreateClaimedAccount(bb, opData);
25285
+ break;
25286
+ case 'account_update2':
25287
+ serializeAccountUpdate2(bb, opData);
25288
+ break;
25289
+ case 'request_account_recovery':
25290
+ serializeRequestAccountRecovery(bb, opData);
25291
+ break;
25292
+ case 'recover_account':
25293
+ serializeRecoverAccount(bb, opData);
25294
+ break;
25295
+ case 'change_recovery_account':
25296
+ serializeChangeRecoveryAccount(bb, opData);
25297
+ break;
25298
+ case 'reset_account':
25299
+ serializeResetAccount(bb, opData);
25300
+ break;
25301
+ case 'set_reset_account':
25302
+ serializeSetResetAccount(bb, opData);
25303
+ break;
25304
+ case 'decline_voting_rights':
25305
+ serializeDeclineVotingRights(bb, opData);
25306
+ break;
25307
+ case 'transfer_to_vesting':
25308
+ serializeTransferToVesting(bb, opData);
25309
+ break;
25310
+ case 'withdraw_vesting':
25311
+ serializeWithdrawVesting(bb, opData);
25312
+ break;
25313
+ case 'set_withdraw_vesting_route':
25314
+ serializeSetWithdrawVestingRoute(bb, opData);
25315
+ break;
25316
+ case 'transfer_to_savings':
25317
+ serializeTransferToSavings(bb, opData);
25318
+ break;
25319
+ case 'transfer_from_savings':
25320
+ serializeTransferFromSavings(bb, opData);
25321
+ break;
25322
+ case 'cancel_transfer_from_savings':
25323
+ serializeCancelTransferFromSavings(bb, opData);
25324
+ break;
25325
+ case 'limit_order_create':
25326
+ serializeLimitOrderCreate(bb, opData);
25327
+ break;
25328
+ case 'limit_order_create2':
25329
+ serializeLimitOrderCreate2(bb, opData);
25330
+ break;
25331
+ case 'limit_order_cancel':
25332
+ serializeLimitOrderCancel(bb, opData);
25333
+ break;
25334
+ case 'feed_publish':
25335
+ serializeFeedPublish(bb, opData);
25336
+ break;
25337
+ case 'convert':
25338
+ serializeConvert(bb, opData);
25339
+ break;
25340
+ case 'fill_order':
25341
+ serializeFillOrder(bb, opData);
25342
+ break;
25343
+ case 'escrow_transfer':
25344
+ serializeEscrowTransfer(bb, opData);
25345
+ break;
25346
+ case 'escrow_dispute':
25347
+ serializeEscrowDispute(bb, opData);
25348
+ break;
25349
+ case 'escrow_release':
25350
+ serializeEscrowRelease(bb, opData);
25351
+ break;
25352
+ case 'escrow_approve':
25353
+ serializeEscrowApprove(bb, opData);
25354
+ break;
25355
+ case 'claim_reward_balance':
25356
+ serializeClaimRewardBalance(bb, opData);
25357
+ break;
25358
+ case 'claim_reward_balance2':
25359
+ serializeClaimRewardBalance2(bb, opData);
25360
+ break;
25361
+ case 'comment_reward':
25362
+ serializeCommentReward(bb, opData);
25363
+ break;
25364
+ case 'liquidity_reward':
25365
+ serializeLiquidityReward(bb, opData);
25366
+ break;
25367
+ case 'interest':
25368
+ serializeInterest(bb, opData);
25369
+ break;
25370
+ case 'fill_vesting_withdraw':
25371
+ serializeFillVestingWithdraw(bb, opData);
25372
+ break;
25373
+ case 'fill_convert_request':
25374
+ serializeFillConvertRequest(bb, opData);
25375
+ break;
25376
+ case 'fill_transfer_from_savings':
25377
+ serializeFillTransferFromSavings(bb, opData);
25378
+ break;
25379
+ case 'pow':
25380
+ serializePow(bb, opData);
25381
+ break;
25382
+ case 'pow2':
25383
+ serializePow2(bb, opData);
25384
+ break;
25385
+ case 'witness_update':
25386
+ serializeWitnessUpdate(bb, opData);
25387
+ break;
25388
+ case 'witness_set_properties':
25389
+ serializeWitnessSetProperties(bb, opData);
25390
+ break;
25391
+ case 'account_witness_vote':
25392
+ serializeAccountWitnessVote(bb, opData);
25393
+ break;
25394
+ case 'account_witness_proxy':
25395
+ serializeAccountWitnessProxy(bb, opData);
25396
+ break;
25397
+ case 'custom':
25398
+ serializeCustom(bb, opData);
25399
+ break;
25400
+ case 'custom_binary':
25401
+ serializeCustomBinary(bb, opData);
25402
+ break;
25403
+ case 'comment_options':
25404
+ serializeCommentOptions(bb, opData);
25405
+ break;
25199
25406
  case 'custom_json':
25200
25407
  serializeCustomJson(bb, opData);
25201
25408
  break;
@@ -25266,143 +25473,843 @@
25266
25473
  writeString(bb, String(dataObj.json_metadata || ''));
25267
25474
  }
25268
25475
  /**
25269
- * Serialize custom_json operation
25476
+ * Serialize account_update operation.
25477
+ * Format: account, optional owner (1 byte + authority?), optional active, optional posting, memo_key, json_metadata.
25270
25478
  */
25271
- function serializeCustomJson(bb, data) {
25479
+ function serializeAccountUpdate(bb, data) {
25272
25480
  const dataObj = data;
25273
- // Serialize required_auths (flat_set<account_name_type>)
25274
- // Set serialization: varint32 length, then each element
25275
- const requiredAuths = Array.isArray(dataObj.required_auths)
25276
- ? dataObj.required_auths.slice().sort()
25277
- : [];
25278
- bb.writeVarint32(requiredAuths.length);
25279
- for (const account of requiredAuths) {
25280
- writeString(bb, String(account));
25481
+ writeString(bb, String(dataObj.account || ''));
25482
+ // Optional authorities: 0 = not present, 1 = present then serialize authority
25483
+ if (dataObj.owner != null && dataObj.owner !== '') {
25484
+ bb.writeUint8(1);
25485
+ serializeAuthority(bb, typeof dataObj.owner === 'object' ? dataObj.owner : { weight_threshold: 1, account_auths: [], key_auths: [] });
25281
25486
  }
25282
- // Serialize required_posting_auths (flat_set<account_name_type>)
25283
- const requiredPostingAuths = Array.isArray(dataObj.required_posting_auths)
25284
- ? dataObj.required_posting_auths.slice().sort()
25285
- : [];
25286
- bb.writeVarint32(requiredPostingAuths.length);
25287
- for (const account of requiredPostingAuths) {
25288
- writeString(bb, String(account));
25487
+ else {
25488
+ bb.writeUint8(0);
25289
25489
  }
25290
- // Serialize id (string)
25291
- writeString(bb, String(dataObj.id || ''));
25292
- // Serialize json (string)
25293
- writeString(bb, String(dataObj.json || '{}'));
25490
+ if (dataObj.active != null && dataObj.active !== '') {
25491
+ bb.writeUint8(1);
25492
+ serializeAuthority(bb, typeof dataObj.active === 'object' ? dataObj.active : { weight_threshold: 1, account_auths: [], key_auths: [] });
25493
+ }
25494
+ else {
25495
+ bb.writeUint8(0);
25496
+ }
25497
+ if (dataObj.posting != null && dataObj.posting !== '') {
25498
+ bb.writeUint8(1);
25499
+ serializeAuthority(bb, typeof dataObj.posting === 'object' ? dataObj.posting : { weight_threshold: 1, account_auths: [], key_auths: [] });
25500
+ }
25501
+ else {
25502
+ bb.writeUint8(0);
25503
+ }
25504
+ // memo_key (public key, required)
25505
+ if (typeof dataObj.memo_key === 'string') {
25506
+ const pubKey = PublicKey.fromStringOrThrow(dataObj.memo_key);
25507
+ bb.append(pubKey.toBuffer());
25508
+ }
25509
+ else if (buffer.Buffer.isBuffer(dataObj.memo_key)) {
25510
+ bb.append(dataObj.memo_key);
25511
+ }
25512
+ else if (dataObj.memo_key && typeof dataObj.memo_key.toBuffer === 'function') {
25513
+ bb.append(dataObj.memo_key.toBuffer());
25514
+ }
25515
+ else {
25516
+ throw new Error('Invalid memo_key format');
25517
+ }
25518
+ writeString(bb, typeof dataObj.json_metadata === 'string'
25519
+ ? dataObj.json_metadata
25520
+ : dataObj.json_metadata != null
25521
+ ? JSON.stringify(dataObj.json_metadata)
25522
+ : '');
25294
25523
  }
25295
25524
  /**
25296
- * Serialize Authority
25525
+ * Serialize account_create_with_delegation operation.
25526
+ * Fields (see FC_REFLECT): fee, delegation, creator, new_account_name,
25527
+ * owner, active, posting, memo_key, json_metadata, extensions.
25297
25528
  */
25298
- function serializeAuthority(bb, auth) {
25299
- const authObj = auth;
25300
- bb.writeUint32(authObj.weight_threshold || 1);
25301
- // Account auths (map<string, uint16>)
25302
- const accountAuths = (Array.isArray(authObj.account_auths) ? authObj.account_auths : []);
25303
- // Maps in Steem serialization are sorted by key
25304
- const accountAuthsArray = accountAuths;
25305
- accountAuthsArray.sort((a, b) => {
25306
- const aKey = Array.isArray(a) && a[0] ? String(a[0]) : '';
25307
- const bKey = Array.isArray(b) && b[0] ? String(b[0]) : '';
25308
- return aKey.localeCompare(bKey);
25309
- });
25310
- bb.writeVarint32(accountAuths.length);
25311
- for (const authEntry of accountAuths) {
25312
- if (Array.isArray(authEntry) && authEntry.length >= 2) {
25313
- writeString(bb, String(authEntry[0]));
25314
- bb.writeUint16(authEntry[1]);
25315
- }
25316
- }
25317
- // Key auths (map<public_key, uint16>)
25318
- const keyAuths = (Array.isArray(authObj.key_auths) ? authObj.key_auths : []);
25319
- // Maps in Steem serialization are sorted by key (public key string)
25320
- // But serialized as bytes. Usually sorting by string representation of public key works.
25321
- const keyAuthsArray = keyAuths;
25322
- keyAuthsArray.sort((a, b) => {
25323
- const aKey = Array.isArray(a) && a[0] ? String(a[0]) : '';
25324
- const bKey = Array.isArray(b) && b[0] ? String(b[0]) : '';
25325
- return aKey.localeCompare(bKey);
25326
- });
25327
- bb.writeVarint32(keyAuths.length);
25328
- for (const keyAuth of keyAuths) {
25329
- if (Array.isArray(keyAuth) && keyAuth.length >= 2) {
25330
- const keyStr = String(keyAuth[0]);
25331
- const weight = keyAuth[1];
25332
- const pubKey = PublicKey.fromStringOrThrow(keyStr);
25333
- bb.append(pubKey.toBuffer());
25334
- bb.writeUint16(weight);
25335
- }
25336
- }
25529
+ function serializeAccountCreateWithDelegation(bb, data) {
25530
+ const dataObj = data;
25531
+ serializeAsset(bb, String(dataObj.fee || '0.000 STEEM'));
25532
+ serializeAsset(bb, String(dataObj.delegation || '0.000 VESTS'));
25533
+ writeString(bb, String(dataObj.creator || ''));
25534
+ writeString(bb, String(dataObj.new_account_name || ''));
25535
+ serializeAuthority(bb, dataObj.owner);
25536
+ serializeAuthority(bb, dataObj.active);
25537
+ serializeAuthority(bb, dataObj.posting);
25538
+ const memoKey = String(dataObj.memo_key || '');
25539
+ const pubKey = PublicKey.fromStringOrThrow(memoKey);
25540
+ bb.append(pubKey.toBuffer());
25541
+ writeString(bb, String(dataObj.json_metadata || ''));
25542
+ serializeExtensions(bb, dataObj.extensions);
25337
25543
  }
25338
25544
  /**
25339
- * Serialize asset (simplified)
25545
+ * Serialize create_claimed_account operation.
25546
+ * Fields: creator, new_account_name, owner, active, posting,
25547
+ * memo_key, json_metadata, extensions.
25340
25548
  */
25341
- function serializeAsset(bb, amount) {
25342
- const parts = amount.split(' ');
25343
- const valueStr = parts[0] || '0.000';
25344
- const symbol = parts[1] || 'STEEM';
25345
- const [intPart, decPart = ''] = valueStr.split('.');
25346
- const precision = decPart.length;
25347
- const amountValue = parseInt(intPart + decPart.padEnd(precision, '0'), 10) || 0;
25348
- // ByteBuffer can accept number directly for small values
25349
- bb.writeInt64(amountValue);
25350
- bb.writeUint8(precision);
25351
- const symbolBytes = buffer.Buffer.from(symbol, 'utf8');
25352
- bb.append(symbolBytes);
25353
- for (let i = symbolBytes.length; i < 7; i++) {
25354
- bb.writeUint8(0);
25355
- }
25549
+ function serializeCreateClaimedAccount(bb, data) {
25550
+ const dataObj = data;
25551
+ writeString(bb, String(dataObj.creator || ''));
25552
+ writeString(bb, String(dataObj.new_account_name || ''));
25553
+ serializeAuthority(bb, dataObj.owner);
25554
+ serializeAuthority(bb, dataObj.active);
25555
+ serializeAuthority(bb, dataObj.posting);
25556
+ const memoKey = String(dataObj.memo_key || '');
25557
+ const pubKey = PublicKey.fromStringOrThrow(memoKey);
25558
+ bb.append(pubKey.toBuffer());
25559
+ writeString(bb, String(dataObj.json_metadata || ''));
25560
+ serializeExtensions(bb, dataObj.extensions);
25356
25561
  }
25357
25562
  /**
25358
- * Write a string using ByteBuffer's writeVString method
25563
+ * Serialize account_update2 operation.
25564
+ * Fields: account, owner, active, posting, memo_key,
25565
+ * json_metadata, posting_json_metadata, extensions.
25359
25566
  */
25360
- function writeString(bb, str) {
25361
- bb.writeVString(str);
25567
+ function serializeAccountUpdate2(bb, data) {
25568
+ const dataObj = data;
25569
+ writeString(bb, String(dataObj.account || ''));
25570
+ serializeAuthority(bb, dataObj.owner);
25571
+ serializeAuthority(bb, dataObj.active);
25572
+ serializeAuthority(bb, dataObj.posting);
25573
+ const memoKey = String(dataObj.memo_key || '');
25574
+ const pubKey = PublicKey.fromStringOrThrow(memoKey);
25575
+ bb.append(pubKey.toBuffer());
25576
+ writeString(bb, String(dataObj.json_metadata || ''));
25577
+ writeString(bb, String(dataObj.posting_json_metadata || ''));
25578
+ serializeExtensions(bb, dataObj.extensions);
25362
25579
  }
25363
-
25364
- class Serializer {
25365
- static fromBuffer(buffer) {
25366
- const bb = ByteBuffer.fromBinary(buffer.toString('binary'), ByteBuffer.LITTLE_ENDIAN);
25367
- // Read public keys
25368
- const fromKey = PublicKey.fromBuffer(bb.readBytes(33).toBuffer());
25369
- const toKey = PublicKey.fromBuffer(bb.readBytes(33).toBuffer());
25370
- // Read nonce (uint64)
25371
- const nonce = bb.readUint64().toString();
25372
- // Read checksum (uint32)
25373
- const check = bb.readUint32();
25374
- // Read encrypted data
25375
- const encryptedLength = bb.readVarint32();
25376
- const encrypted = bb.readBytes(encryptedLength).toString('hex');
25377
- return {
25378
- from: fromKey,
25379
- to: toKey,
25380
- nonce,
25381
- check,
25382
- encrypted
25383
- };
25384
- }
25385
- static toBuffer(memo) {
25386
- const bb = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
25387
- // Write public keys
25388
- bb.append(memo.from.toBuffer());
25389
- bb.append(memo.to.toBuffer());
25390
- // Write nonce (uint64) - handle both string and number
25391
- let nonceLong;
25392
- if (typeof memo.nonce === 'string') {
25393
- // Use Long.fromString with unsigned flag for large numbers
25394
- try {
25580
+ /**
25581
+ * Serialize request_account_recovery operation.
25582
+ * Fields: recovery_account, account_to_recover, new_owner_authority, extensions.
25583
+ */
25584
+ function serializeRequestAccountRecovery(bb, data) {
25585
+ const dataObj = data;
25586
+ writeString(bb, String(dataObj.recovery_account || ''));
25587
+ writeString(bb, String(dataObj.account_to_recover || ''));
25588
+ serializeAuthority(bb, dataObj.new_owner_authority);
25589
+ serializeExtensions(bb, dataObj.extensions);
25590
+ }
25591
+ /**
25592
+ * Serialize recover_account operation.
25593
+ * Fields: account_to_recover, new_owner_authority, recent_owner_authority, extensions.
25594
+ */
25595
+ function serializeRecoverAccount(bb, data) {
25596
+ const dataObj = data;
25597
+ writeString(bb, String(dataObj.account_to_recover || ''));
25598
+ serializeAuthority(bb, dataObj.new_owner_authority);
25599
+ serializeAuthority(bb, dataObj.recent_owner_authority);
25600
+ serializeExtensions(bb, dataObj.extensions);
25601
+ }
25602
+ /**
25603
+ * Serialize change_recovery_account operation.
25604
+ * Fields: account_to_recover, new_recovery_account, extensions.
25605
+ */
25606
+ function serializeChangeRecoveryAccount(bb, data) {
25607
+ const dataObj = data;
25608
+ writeString(bb, String(dataObj.account_to_recover || ''));
25609
+ writeString(bb, String(dataObj.new_recovery_account || ''));
25610
+ serializeExtensions(bb, dataObj.extensions);
25611
+ }
25612
+ /**
25613
+ * Serialize reset_account operation.
25614
+ * Fields: reset_account, account_to_reset, new_owner_authority.
25615
+ */
25616
+ function serializeResetAccount(bb, data) {
25617
+ const dataObj = data;
25618
+ writeString(bb, String(dataObj.reset_account || ''));
25619
+ writeString(bb, String(dataObj.account_to_reset || ''));
25620
+ serializeAuthority(bb, dataObj.new_owner_authority);
25621
+ }
25622
+ /**
25623
+ * Serialize set_reset_account operation.
25624
+ * Fields: account, reset_account.
25625
+ */
25626
+ function serializeSetResetAccount(bb, data) {
25627
+ const dataObj = data;
25628
+ writeString(bb, String(dataObj.account || ''));
25629
+ writeString(bb, String(dataObj.reset_account || ''));
25630
+ }
25631
+ /**
25632
+ * Serialize decline_voting_rights operation.
25633
+ * Fields: account, decline.
25634
+ */
25635
+ function serializeDeclineVotingRights(bb, data) {
25636
+ const dataObj = data;
25637
+ writeString(bb, String(dataObj.account || ''));
25638
+ serializeBool(bb, dataObj.decline);
25639
+ }
25640
+ /**
25641
+ * Serialize transfer_to_vesting operation.
25642
+ * Fields: from, to, amount.
25643
+ */
25644
+ function serializeTransferToVesting(bb, data) {
25645
+ const dataObj = data;
25646
+ writeString(bb, String(dataObj.from || ''));
25647
+ writeString(bb, String(dataObj.to || ''));
25648
+ serializeAsset(bb, String(dataObj.amount || '0.000 STEEM'));
25649
+ }
25650
+ /**
25651
+ * Serialize withdraw_vesting operation.
25652
+ * Fields: account, vesting_shares.
25653
+ */
25654
+ function serializeWithdrawVesting(bb, data) {
25655
+ const dataObj = data;
25656
+ writeString(bb, String(dataObj.account || ''));
25657
+ serializeAsset(bb, String(dataObj.vesting_shares || '0.000 VESTS'));
25658
+ }
25659
+ /**
25660
+ * Serialize set_withdraw_vesting_route operation.
25661
+ * Fields: from_account, to_account, percent, auto_vest.
25662
+ */
25663
+ function serializeSetWithdrawVestingRoute(bb, data) {
25664
+ const dataObj = data;
25665
+ writeString(bb, String(dataObj.from_account || ''));
25666
+ writeString(bb, String(dataObj.to_account || ''));
25667
+ // percent is uint16
25668
+ bb.writeUint16(dataObj.percent ?? 0);
25669
+ serializeBool(bb, dataObj.auto_vest);
25670
+ }
25671
+ /**
25672
+ * Serialize transfer_to_savings operation.
25673
+ * Fields: from, to, amount, memo.
25674
+ */
25675
+ function serializeTransferToSavings(bb, data) {
25676
+ const dataObj = data;
25677
+ writeString(bb, String(dataObj.from || ''));
25678
+ writeString(bb, String(dataObj.to || ''));
25679
+ serializeAsset(bb, String(dataObj.amount || '0.000 STEEM'));
25680
+ writeString(bb, String(dataObj.memo || ''));
25681
+ }
25682
+ /**
25683
+ * Serialize transfer_from_savings operation.
25684
+ * Fields: from, request_id, to, amount, memo.
25685
+ */
25686
+ function serializeTransferFromSavings(bb, data) {
25687
+ const dataObj = data;
25688
+ writeString(bb, String(dataObj.from || ''));
25689
+ bb.writeUint32(dataObj.request_id ?? dataObj.requestID ?? 0);
25690
+ writeString(bb, String(dataObj.to || ''));
25691
+ serializeAsset(bb, String(dataObj.amount || '0.000 STEEM'));
25692
+ writeString(bb, String(dataObj.memo || ''));
25693
+ }
25694
+ /**
25695
+ * Serialize cancel_transfer_from_savings operation.
25696
+ * Fields: from, request_id.
25697
+ */
25698
+ function serializeCancelTransferFromSavings(bb, data) {
25699
+ const dataObj = data;
25700
+ writeString(bb, String(dataObj.from || ''));
25701
+ bb.writeUint32(dataObj.request_id ?? dataObj.requestID ?? 0);
25702
+ }
25703
+ /**
25704
+ * Serialize limit_order_create operation.
25705
+ * Fields: owner, orderid, amount_to_sell, min_to_receive, fill_or_kill, expiration.
25706
+ */
25707
+ function serializeLimitOrderCreate(bb, data) {
25708
+ const dataObj = data;
25709
+ writeString(bb, String(dataObj.owner || ''));
25710
+ bb.writeUint32(dataObj.orderid ?? 0);
25711
+ serializeAsset(bb, String(dataObj.amount_to_sell || '0.000 STEEM'));
25712
+ serializeAsset(bb, String(dataObj.min_to_receive || '0.000 STEEM'));
25713
+ serializeBool(bb, dataObj.fill_or_kill);
25714
+ serializeTimePointSec(bb, dataObj.expiration);
25715
+ }
25716
+ /**
25717
+ * Serialize limit_order_create2 operation.
25718
+ * Fields: owner, orderid, amount_to_sell, exchange_rate{base, quote}, fill_or_kill, expiration.
25719
+ */
25720
+ function serializeLimitOrderCreate2(bb, data) {
25721
+ const dataObj = data;
25722
+ writeString(bb, String(dataObj.owner || ''));
25723
+ bb.writeUint32(dataObj.orderid ?? 0);
25724
+ serializeAsset(bb, String(dataObj.amount_to_sell || '0.000 STEEM'));
25725
+ const rate = (dataObj.exchange_rate ?? dataObj.exchangeRate);
25726
+ const base = rate?.base ?? '0.000 STEEM';
25727
+ const quote = rate?.quote ?? '0.000 SBD';
25728
+ serializeAsset(bb, String(base));
25729
+ serializeAsset(bb, String(quote));
25730
+ serializeBool(bb, dataObj.fill_or_kill);
25731
+ serializeTimePointSec(bb, dataObj.expiration);
25732
+ }
25733
+ /**
25734
+ * Serialize limit_order_cancel operation.
25735
+ * Fields: owner, orderid.
25736
+ */
25737
+ function serializeLimitOrderCancel(bb, data) {
25738
+ const dataObj = data;
25739
+ writeString(bb, String(dataObj.owner || ''));
25740
+ bb.writeUint32(dataObj.orderid ?? 0);
25741
+ }
25742
+ /**
25743
+ * Serialize feed_publish operation.
25744
+ * Fields: publisher, exchange_rate{base, quote}.
25745
+ */
25746
+ function serializeFeedPublish(bb, data) {
25747
+ const dataObj = data;
25748
+ writeString(bb, String(dataObj.publisher || ''));
25749
+ const rate = (dataObj.exchange_rate ?? dataObj.exchangeRate);
25750
+ const base = rate?.base ?? '0.000 STEEM';
25751
+ const quote = rate?.quote ?? '0.000 SBD';
25752
+ serializeAsset(bb, String(base));
25753
+ serializeAsset(bb, String(quote));
25754
+ }
25755
+ /**
25756
+ * Serialize convert operation.
25757
+ * Fields: owner, requestid, amount.
25758
+ */
25759
+ function serializeConvert(bb, data) {
25760
+ const dataObj = data;
25761
+ writeString(bb, String(dataObj.owner || ''));
25762
+ bb.writeUint32(dataObj.requestid ?? dataObj.request_id ?? 0);
25763
+ serializeAsset(bb, String(dataObj.amount || '0.000 STEEM'));
25764
+ }
25765
+ /**
25766
+ * Serialize fill_order operation (virtual).
25767
+ * Fields: current_owner, current_orderid, current_pays,
25768
+ * open_owner, open_orderid, open_pays.
25769
+ */
25770
+ function serializeFillOrder(bb, data) {
25771
+ const dataObj = data;
25772
+ writeString(bb, String(dataObj.current_owner || ''));
25773
+ bb.writeUint32(dataObj.current_orderid ?? 0);
25774
+ serializeAsset(bb, String(dataObj.current_pays || '0.000 STEEM'));
25775
+ writeString(bb, String(dataObj.open_owner || ''));
25776
+ bb.writeUint32(dataObj.open_orderid ?? 0);
25777
+ serializeAsset(bb, String(dataObj.open_pays || '0.000 STEEM'));
25778
+ }
25779
+ /**
25780
+ * Serialize escrow_transfer operation.
25781
+ * Fields: from, to, sbd_amount, steem_amount, escrow_id, agent,
25782
+ * fee, json_meta, ratification_deadline, escrow_expiration.
25783
+ */
25784
+ function serializeEscrowTransfer(bb, data) {
25785
+ const dataObj = data;
25786
+ writeString(bb, String(dataObj.from || ''));
25787
+ writeString(bb, String(dataObj.to || ''));
25788
+ serializeAsset(bb, String(dataObj.sbd_amount || '0.000 SBD'));
25789
+ serializeAsset(bb, String(dataObj.steem_amount || '0.000 STEEM'));
25790
+ bb.writeUint32(dataObj.escrow_id ?? 0);
25791
+ writeString(bb, String(dataObj.agent || ''));
25792
+ serializeAsset(bb, String(dataObj.fee || '0.000 STEEM'));
25793
+ writeString(bb, String(dataObj.json_meta || ''));
25794
+ serializeTimePointSec(bb, dataObj.ratification_deadline);
25795
+ serializeTimePointSec(bb, dataObj.escrow_expiration);
25796
+ }
25797
+ /**
25798
+ * Serialize escrow_dispute operation.
25799
+ * Fields: from, to, who, escrow_id.
25800
+ */
25801
+ function serializeEscrowDispute(bb, data) {
25802
+ const dataObj = data;
25803
+ writeString(bb, String(dataObj.from || ''));
25804
+ writeString(bb, String(dataObj.to || ''));
25805
+ writeString(bb, String(dataObj.who || ''));
25806
+ bb.writeUint32(dataObj.escrow_id ?? 0);
25807
+ }
25808
+ /**
25809
+ * Serialize escrow_release operation.
25810
+ * Fields: from, to, who, escrow_id, sbd_amount, steem_amount.
25811
+ */
25812
+ function serializeEscrowRelease(bb, data) {
25813
+ const dataObj = data;
25814
+ writeString(bb, String(dataObj.from || ''));
25815
+ writeString(bb, String(dataObj.to || ''));
25816
+ writeString(bb, String(dataObj.who || ''));
25817
+ bb.writeUint32(dataObj.escrow_id ?? 0);
25818
+ serializeAsset(bb, String(dataObj.sbd_amount || '0.000 SBD'));
25819
+ serializeAsset(bb, String(dataObj.steem_amount || '0.000 STEEM'));
25820
+ }
25821
+ /**
25822
+ * Serialize escrow_approve operation.
25823
+ * Fields: from, to, agent, who, escrow_id, approve.
25824
+ */
25825
+ function serializeEscrowApprove(bb, data) {
25826
+ const dataObj = data;
25827
+ writeString(bb, String(dataObj.from || ''));
25828
+ writeString(bb, String(dataObj.to || ''));
25829
+ writeString(bb, String(dataObj.agent || ''));
25830
+ writeString(bb, String(dataObj.who || ''));
25831
+ bb.writeUint32(dataObj.escrow_id ?? 0);
25832
+ serializeBool(bb, dataObj.approve);
25833
+ }
25834
+ /**
25835
+ * Serialize claim_reward_balance operation.
25836
+ * Fields: account, reward_steem, reward_sbd, reward_vests.
25837
+ */
25838
+ function serializeClaimRewardBalance(bb, data) {
25839
+ const dataObj = data;
25840
+ writeString(bb, String(dataObj.account || ''));
25841
+ serializeAsset(bb, String(dataObj.reward_steem || '0.000 STEEM'));
25842
+ serializeAsset(bb, String(dataObj.reward_sbd || '0.000 SBD'));
25843
+ serializeAsset(bb, String(dataObj.reward_vests || '0.000000 VESTS'));
25844
+ }
25845
+ /**
25846
+ * Serialize claim_reward_balance2 operation.
25847
+ * Fields: account, extensions, reward_tokens (array of asset strings).
25848
+ */
25849
+ function serializeClaimRewardBalance2(bb, data) {
25850
+ const dataObj = data;
25851
+ writeString(bb, String(dataObj.account || ''));
25852
+ serializeExtensions(bb, dataObj.extensions);
25853
+ const tokens = Array.isArray(dataObj.reward_tokens) ? dataObj.reward_tokens : [];
25854
+ bb.writeVarint32(tokens.length);
25855
+ for (const tok of tokens) {
25856
+ serializeAsset(bb, typeof tok === 'string' ? tok : String(tok));
25857
+ }
25858
+ }
25859
+ /**
25860
+ * Serialize comment_reward operation.
25861
+ * Fields: author, permlink, payout.
25862
+ */
25863
+ function serializeCommentReward(bb, data) {
25864
+ const dataObj = data;
25865
+ writeString(bb, String(dataObj.author || ''));
25866
+ writeString(bb, String(dataObj.permlink || ''));
25867
+ serializeAsset(bb, String(dataObj.payout || '0.000 STEEM'));
25868
+ }
25869
+ /**
25870
+ * Serialize liquidity_reward operation.
25871
+ * Fields: owner, payout.
25872
+ */
25873
+ function serializeLiquidityReward(bb, data) {
25874
+ const dataObj = data;
25875
+ writeString(bb, String(dataObj.owner || ''));
25876
+ serializeAsset(bb, String(dataObj.payout || '0.000 STEEM'));
25877
+ }
25878
+ /**
25879
+ * Serialize interest operation.
25880
+ * Fields: owner, interest.
25881
+ */
25882
+ function serializeInterest(bb, data) {
25883
+ const dataObj = data;
25884
+ writeString(bb, String(dataObj.owner || ''));
25885
+ serializeAsset(bb, String(dataObj.interest || '0.000 STEEM'));
25886
+ }
25887
+ /**
25888
+ * Serialize fill_vesting_withdraw operation.
25889
+ * Fields: from_account, to_account, withdrawn, deposited.
25890
+ */
25891
+ function serializeFillVestingWithdraw(bb, data) {
25892
+ const dataObj = data;
25893
+ writeString(bb, String(dataObj.from_account || ''));
25894
+ writeString(bb, String(dataObj.to_account || ''));
25895
+ serializeAsset(bb, String(dataObj.withdrawn || '0.000000 VESTS'));
25896
+ serializeAsset(bb, String(dataObj.deposited || '0.000 STEEM'));
25897
+ }
25898
+ /**
25899
+ * Serialize fill_convert_request operation.
25900
+ * Fields: owner, requestid, amount_in, amount_out.
25901
+ */
25902
+ function serializeFillConvertRequest(bb, data) {
25903
+ const dataObj = data;
25904
+ writeString(bb, String(dataObj.owner || ''));
25905
+ bb.writeUint32(dataObj.requestid ?? 0);
25906
+ serializeAsset(bb, String(dataObj.amount_in || '0.000 STEEM'));
25907
+ serializeAsset(bb, String(dataObj.amount_out || '0.000 STEEM'));
25908
+ }
25909
+ /**
25910
+ * Serialize fill_transfer_from_savings operation.
25911
+ * Fields: from, to, amount, request_id, memo.
25912
+ */
25913
+ function serializeFillTransferFromSavings(bb, data) {
25914
+ const dataObj = data;
25915
+ writeString(bb, String(dataObj.from || ''));
25916
+ writeString(bb, String(dataObj.to || ''));
25917
+ serializeAsset(bb, String(dataObj.amount || '0.000 STEEM'));
25918
+ bb.writeUint32(dataObj.request_id ?? 0);
25919
+ writeString(bb, String(dataObj.memo || ''));
25920
+ }
25921
+ /**
25922
+ * Serialize ChainProperties (used in pow, witness_update).
25923
+ * Fields: account_creation_fee (asset string), maximum_block_size (uint32), sbd_interest_rate (uint16).
25924
+ */
25925
+ function serializeChainProperties(bb, props) {
25926
+ const p = props || {};
25927
+ const fee = p.account_creation_fee;
25928
+ if (typeof fee === 'string' && fee.split(' ').length >= 2) {
25929
+ serializeAsset(bb, fee);
25930
+ }
25931
+ else {
25932
+ serializeAsset(bb, '0.000 STEEM');
25933
+ }
25934
+ bb.writeUint32(p.maximum_block_size ?? 0);
25935
+ bb.writeUint16(p.sbd_interest_rate ?? 0);
25936
+ }
25937
+ /**
25938
+ * Serialize POW inner struct (worker, input, signature, work).
25939
+ */
25940
+ function serializePOWInner(bb, work) {
25941
+ const w = work || {};
25942
+ writeString(bb, String(w.worker || ''));
25943
+ writeString(bb, String(w.input || ''));
25944
+ writeString(bb, String(w.signature || ''));
25945
+ writeString(bb, String(w.work || ''));
25946
+ }
25947
+ /**
25948
+ * Serialize pow operation.
25949
+ * Fields: worker_account, block_id, nonce (optional), work (POW), props (ChainProperties).
25950
+ */
25951
+ function serializePow(bb, data) {
25952
+ const dataObj = data;
25953
+ writeString(bb, String(dataObj.worker_account || ''));
25954
+ writeString(bb, String(dataObj.block_id || ''));
25955
+ const nonce = dataObj.nonce;
25956
+ if (nonce !== undefined && nonce !== null) {
25957
+ bb.writeUint8(1);
25958
+ bb.writeUint64(Number(nonce));
25959
+ }
25960
+ else {
25961
+ bb.writeUint8(0);
25962
+ }
25963
+ serializePOWInner(bb, dataObj.work);
25964
+ serializeChainProperties(bb, dataObj.props);
25965
+ }
25966
+ /**
25967
+ * Serialize pow2 operation.
25968
+ * Fields: input, pow_summary (opaque bytes; if string treated as hex).
25969
+ */
25970
+ function serializePow2(bb, data) {
25971
+ const dataObj = data;
25972
+ writeString(bb, String(dataObj.input || ''));
25973
+ const summary = dataObj.pow_summary;
25974
+ let bytes;
25975
+ if (typeof summary === 'string') {
25976
+ const hex = summary.startsWith('0x') ? summary.slice(2) : summary;
25977
+ bytes = buffer.Buffer.from(hex, 'hex');
25978
+ }
25979
+ else if (buffer.Buffer.isBuffer(summary)) {
25980
+ bytes = summary;
25981
+ }
25982
+ else {
25983
+ bytes = buffer.Buffer.alloc(0);
25984
+ }
25985
+ bb.writeVarint32(bytes.length);
25986
+ bb.append(bytes);
25987
+ }
25988
+ /**
25989
+ * Serialize witness_update operation.
25990
+ * Fields: owner, url, block_signing_key, props (ChainProperties), fee.
25991
+ */
25992
+ function serializeWitnessUpdate(bb, data) {
25993
+ const dataObj = data;
25994
+ writeString(bb, String(dataObj.owner || ''));
25995
+ writeString(bb, String(dataObj.url || ''));
25996
+ const key = dataObj.block_signing_key;
25997
+ if (typeof key === 'string') {
25998
+ const pubKey = PublicKey.fromStringOrThrow(key);
25999
+ bb.append(pubKey.toBuffer());
26000
+ }
26001
+ else if (buffer.Buffer.isBuffer(key)) {
26002
+ bb.append(key);
26003
+ }
26004
+ else if (key && typeof key.toBuffer === 'function') {
26005
+ bb.append(key.toBuffer());
26006
+ }
26007
+ else {
26008
+ bb.append(buffer.Buffer.alloc(33));
26009
+ }
26010
+ serializeChainProperties(bb, dataObj.props);
26011
+ serializeAsset(bb, String(dataObj.fee || '0.000 STEEM'));
26012
+ }
26013
+ /**
26014
+ * Serialize witness_set_properties operation.
26015
+ * Fields: owner, props (map string -> bytes), extensions.
26016
+ */
26017
+ function serializeWitnessSetProperties(bb, data) {
26018
+ const dataObj = data;
26019
+ writeString(bb, String(dataObj.owner || ''));
26020
+ const props = dataObj.props;
26021
+ const keys = props ? Object.keys(props).sort() : [];
26022
+ bb.writeVarint32(keys.length);
26023
+ for (const k of keys) {
26024
+ writeString(bb, k);
26025
+ const v = props[k];
26026
+ const buf = typeof v === 'string' ? buffer.Buffer.from(v, 'utf8') : buffer.Buffer.isBuffer(v) ? v : buffer.Buffer.alloc(0);
26027
+ bb.writeVarint32(buf.length);
26028
+ bb.append(buf);
26029
+ }
26030
+ serializeExtensions(bb, dataObj.extensions);
26031
+ }
26032
+ /**
26033
+ * Serialize account_witness_vote operation.
26034
+ * Fields: account, witness, approve.
26035
+ */
26036
+ function serializeAccountWitnessVote(bb, data) {
26037
+ const dataObj = data;
26038
+ writeString(bb, String(dataObj.account || ''));
26039
+ writeString(bb, String(dataObj.witness || ''));
26040
+ serializeBool(bb, dataObj.approve);
26041
+ }
26042
+ /**
26043
+ * Serialize account_witness_proxy operation.
26044
+ * Fields: account, proxy.
26045
+ */
26046
+ function serializeAccountWitnessProxy(bb, data) {
26047
+ const dataObj = data;
26048
+ writeString(bb, String(dataObj.account || ''));
26049
+ writeString(bb, String(dataObj.proxy || ''));
26050
+ }
26051
+ /**
26052
+ * Serialize custom operation (required_auths, id, data).
26053
+ * id is uint16 in protocol; data is bytes.
26054
+ */
26055
+ function serializeCustom(bb, data) {
26056
+ const dataObj = data;
26057
+ const requiredAuths = Array.isArray(dataObj.required_auths)
26058
+ ? dataObj.required_auths.slice().sort()
26059
+ : [];
26060
+ bb.writeVarint32(requiredAuths.length);
26061
+ for (const account of requiredAuths) {
26062
+ writeString(bb, String(account));
26063
+ }
26064
+ bb.writeUint16(dataObj.id ?? 0);
26065
+ const dataBytes = dataObj.data;
26066
+ let buf;
26067
+ if (typeof dataBytes === 'string') {
26068
+ const hex = dataBytes.startsWith('0x') ? dataBytes.slice(2) : dataBytes;
26069
+ buf = buffer.Buffer.from(hex, 'hex');
26070
+ }
26071
+ else if (buffer.Buffer.isBuffer(dataBytes)) {
26072
+ buf = dataBytes;
26073
+ }
26074
+ else {
26075
+ buf = buffer.Buffer.alloc(0);
26076
+ }
26077
+ bb.writeVarint32(buf.length);
26078
+ bb.append(buf);
26079
+ }
26080
+ /**
26081
+ * Serialize custom_binary operation.
26082
+ * Fields: id (string), data (bytes).
26083
+ */
26084
+ function serializeCustomBinary(bb, data) {
26085
+ const dataObj = data;
26086
+ writeString(bb, String(dataObj.id || ''));
26087
+ const dataBytes = dataObj.data;
26088
+ let buf;
26089
+ if (typeof dataBytes === 'string') {
26090
+ const hex = dataBytes.startsWith('0x') ? dataBytes.slice(2) : dataBytes;
26091
+ buf = buffer.Buffer.from(hex, 'hex');
26092
+ }
26093
+ else if (buffer.Buffer.isBuffer(dataBytes)) {
26094
+ buf = dataBytes;
26095
+ }
26096
+ else {
26097
+ buf = buffer.Buffer.alloc(0);
26098
+ }
26099
+ bb.writeVarint32(buf.length);
26100
+ bb.append(buf);
26101
+ }
26102
+ /**
26103
+ * Serialize comment_options operation.
26104
+ * Fields: author, permlink, max_accepted_payout, percent_steem_dollars, allow_votes, allow_curation_rewards, extensions.
26105
+ */
26106
+ function serializeCommentOptions(bb, data) {
26107
+ const dataObj = data;
26108
+ writeString(bb, String(dataObj.author || ''));
26109
+ writeString(bb, String(dataObj.permlink || ''));
26110
+ serializeAsset(bb, String(dataObj.max_accepted_payout || '1000000.000 SBD'));
26111
+ bb.writeUint16(dataObj.percent_steem_dollars ?? 0);
26112
+ serializeBool(bb, dataObj.allow_votes);
26113
+ serializeBool(bb, dataObj.allow_curation_rewards);
26114
+ serializeExtensions(bb, dataObj.extensions);
26115
+ }
26116
+ /**
26117
+ * Serialize custom_json operation
26118
+ */
26119
+ function serializeCustomJson(bb, data) {
26120
+ const dataObj = data;
26121
+ // Serialize required_auths (flat_set<account_name_type>)
26122
+ // Set serialization: varint32 length, then each element
26123
+ const requiredAuths = Array.isArray(dataObj.required_auths)
26124
+ ? dataObj.required_auths.slice().sort()
26125
+ : [];
26126
+ bb.writeVarint32(requiredAuths.length);
26127
+ for (const account of requiredAuths) {
26128
+ writeString(bb, String(account));
26129
+ }
26130
+ // Serialize required_posting_auths (flat_set<account_name_type>)
26131
+ const requiredPostingAuths = Array.isArray(dataObj.required_posting_auths)
26132
+ ? dataObj.required_posting_auths.slice().sort()
26133
+ : [];
26134
+ bb.writeVarint32(requiredPostingAuths.length);
26135
+ for (const account of requiredPostingAuths) {
26136
+ writeString(bb, String(account));
26137
+ }
26138
+ // Serialize id (string)
26139
+ writeString(bb, String(dataObj.id || ''));
26140
+ // Serialize json (string)
26141
+ writeString(bb, String(dataObj.json || '{}'));
26142
+ }
26143
+ /**
26144
+ * Serialize Authority
26145
+ */
26146
+ function serializeAuthority(bb, auth) {
26147
+ const authObj = auth;
26148
+ bb.writeUint32(authObj.weight_threshold || 1);
26149
+ // Account auths (map<string, uint16>)
26150
+ const accountAuths = (Array.isArray(authObj.account_auths) ? authObj.account_auths : []);
26151
+ // Maps in Steem serialization are sorted by key
26152
+ const accountAuthsArray = accountAuths;
26153
+ accountAuthsArray.sort((a, b) => {
26154
+ const aKey = Array.isArray(a) && a[0] ? String(a[0]) : '';
26155
+ const bKey = Array.isArray(b) && b[0] ? String(b[0]) : '';
26156
+ return aKey.localeCompare(bKey);
26157
+ });
26158
+ bb.writeVarint32(accountAuths.length);
26159
+ for (const authEntry of accountAuths) {
26160
+ if (Array.isArray(authEntry) && authEntry.length >= 2) {
26161
+ writeString(bb, String(authEntry[0]));
26162
+ bb.writeUint16(authEntry[1]);
26163
+ }
26164
+ }
26165
+ // Key auths (map<public_key, uint16>)
26166
+ const keyAuths = (Array.isArray(authObj.key_auths) ? authObj.key_auths : []);
26167
+ // Maps in Steem serialization are sorted by key (public key string)
26168
+ // But serialized as bytes. Usually sorting by string representation of public key works.
26169
+ const keyAuthsArray = keyAuths;
26170
+ keyAuthsArray.sort((a, b) => {
26171
+ const aKey = Array.isArray(a) && a[0] ? String(a[0]) : '';
26172
+ const bKey = Array.isArray(b) && b[0] ? String(b[0]) : '';
26173
+ return aKey.localeCompare(bKey);
26174
+ });
26175
+ bb.writeVarint32(keyAuths.length);
26176
+ for (const keyAuth of keyAuths) {
26177
+ if (Array.isArray(keyAuth) && keyAuth.length >= 2) {
26178
+ const keyStr = String(keyAuth[0]);
26179
+ const weight = keyAuth[1];
26180
+ const pubKey = PublicKey.fromStringOrThrow(keyStr);
26181
+ bb.append(pubKey.toBuffer());
26182
+ bb.writeUint16(weight);
26183
+ }
26184
+ }
26185
+ }
26186
+ /**
26187
+ * Serialize asset (STEEM/SBD/VESTS style string) to binary.
26188
+ *
26189
+ * Format: int64 amount (little-endian) + uint8 precision + 7-byte symbol (UTF-8, null-padded).
26190
+ *
26191
+ * This helper is reused across all operations中涉及资产字段的地方,例如:
26192
+ * - amount / vesting_shares / reward_* / *_pays
26193
+ */
26194
+ function serializeAsset(bb, amount) {
26195
+ const parts = amount.split(' ');
26196
+ const valueStr = parts[0] || '0.000';
26197
+ const symbol = parts[1] || 'STEEM';
26198
+ const [intPart, decPart = ''] = valueStr.split('.');
26199
+ const precision = decPart.length;
26200
+ const amountValue = parseInt(intPart + decPart.padEnd(precision, '0'), 10) || 0;
26201
+ bb.writeInt64(amountValue);
26202
+ bb.writeUint8(precision);
26203
+ const symbolBytes = buffer.Buffer.from(symbol, 'utf8');
26204
+ bb.append(symbolBytes);
26205
+ for (let i = symbolBytes.length; i < 7; i++) {
26206
+ bb.writeUint8(0);
26207
+ }
26208
+ }
26209
+ /**
26210
+ * Write a string using ByteBuffer's writeVString method.
26211
+ * 所有字符串字段统一通过该 helper 序列化,避免直接到处调用 ByteBuffer API。
26212
+ */
26213
+ function writeString(bb, str) {
26214
+ bb.writeVString(str);
26215
+ }
26216
+ /**
26217
+ * Serialize a time_point_sec-style field.
26218
+ *
26219
+ * 接受 ISO 字符串 / Date / 秒级数字,最终写入 uint32(自 epoch 起的秒数)。
26220
+ * 常用于 proposal start/end、escrow_deadline 等字段。
26221
+ */
26222
+ function serializeTimePointSec(bb, value) {
26223
+ let seconds;
26224
+ if (typeof value === 'string') {
26225
+ const iso = value.endsWith('Z') ? value : `${value}Z`;
26226
+ const d = new Date(iso);
26227
+ seconds = Math.floor(d.getTime() / 1000);
26228
+ }
26229
+ else if (value instanceof Date) {
26230
+ seconds = Math.floor(value.getTime() / 1000);
26231
+ }
26232
+ else if (typeof value === 'number') {
26233
+ // 这里假定已是秒级时间戳
26234
+ seconds = value;
26235
+ }
26236
+ else {
26237
+ seconds = 0;
26238
+ }
26239
+ bb.writeUint32(seconds);
26240
+ }
26241
+ /**
26242
+ * Serialize a generic bool flag as uint8(0/1).
26243
+ * 后续在多处 optional / approve / decline 字段可统一复用。
26244
+ */
26245
+ function serializeBool(bb, value) {
26246
+ bb.writeUint8(value ? 1 : 0);
26247
+ }
26248
+ /**
26249
+ * Serialize a future_extensions / extensions 风格字段。
26250
+ *
26251
+ * 目前大多数链上交易中 extensions 仍为空集合,协议格式是:
26252
+ * - varint32 length
26253
+ * - 后续按约定序列化各元素(当前实现仅支持空或简单 JSON 字符串)
26254
+ *
26255
+ * 为兼容现有使用场景,这里暂时只写入长度,忽略实际内容;当需要支持
26256
+ * 具体 extension 类型时,可以在保持签名兼容性的前提下扩展实现。
26257
+ */
26258
+ function serializeExtensions(bb, extensions) {
26259
+ if (!Array.isArray(extensions) || extensions.length === 0) {
26260
+ bb.writeVarint32(0);
26261
+ return;
26262
+ }
26263
+ // 协议上 extensions 是 future_extensions,目前主网基本为 0。
26264
+ // 为避免序列化出与 C++ 节点不兼容的数据,这里保守起见仍写入 0。
26265
+ // 如果未来需要支持非空 extensions,可在测试验证后放开以下逻辑:
26266
+ //
26267
+ // bb.writeVarint32(extensions.length);
26268
+ // for (const ext of extensions) {
26269
+ // const json = JSON.stringify(ext ?? null);
26270
+ // writeString(bb, json);
26271
+ // }
26272
+ bb.writeVarint32(0);
26273
+ }
26274
+
26275
+ class Serializer {
26276
+ static fromBuffer(buffer) {
26277
+ const bb = ByteBuffer.fromBinary(buffer.toString('binary'), ByteBuffer.LITTLE_ENDIAN);
26278
+ // Require at least 66 bytes for two 33-byte public keys before reading
26279
+ if (bb.remaining() < 66) {
26280
+ throw new Error('Invalid memo: insufficient data for public keys');
26281
+ }
26282
+ // Read public keys
26283
+ const fromKey = PublicKey.fromBuffer(bb.readBytes(33).toBuffer());
26284
+ const toKey = PublicKey.fromBuffer(bb.readBytes(33).toBuffer());
26285
+ // Read nonce (uint64)
26286
+ const nonce = bb.readUint64().toString();
26287
+ // Read checksum (uint32)
26288
+ const check = bb.readUint32();
26289
+ // Read encrypted data
26290
+ const encryptedLength = bb.readVarint32();
26291
+ const encrypted = bb.readBytes(encryptedLength).toString('hex');
26292
+ return {
26293
+ from: fromKey,
26294
+ to: toKey,
26295
+ nonce,
26296
+ check,
26297
+ encrypted
26298
+ };
26299
+ }
26300
+ static toBuffer(memo) {
26301
+ const bb = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
26302
+ // Write public keys
26303
+ bb.append(memo.from.toBuffer());
26304
+ bb.append(memo.to.toBuffer());
26305
+ // Write nonce (uint64) - must be string representing unsigned 64-bit integer
26306
+ let nonceLong;
26307
+ if (typeof memo.nonce === 'string') {
26308
+ try {
25395
26309
  nonceLong = Long.fromString(memo.nonce, true, 10); // unsigned, base 10
25396
26310
  }
25397
26311
  catch {
25398
- // Fallback: try as number if string parsing fails
25399
- const num = Number(memo.nonce);
25400
- if (!isNaN(num) && isFinite(num)) {
25401
- nonceLong = Long.fromNumber(num, true); // unsigned
25402
- }
25403
- else {
25404
- throw new Error(`Invalid nonce format: ${memo.nonce}`);
25405
- }
26312
+ throw new Error(`Invalid nonce format: ${memo.nonce}. Must be a string representing an unsigned 64-bit integer.`);
25406
26313
  }
25407
26314
  }
25408
26315
  else {
@@ -25424,7 +26331,7 @@
25424
26331
  const transaction = {
25425
26332
  toBuffer(trx) {
25426
26333
  // Use binary serialization for proper signature generation
25427
- return serializeTransaction$1(trx);
26334
+ return serializeTransaction(trx);
25428
26335
  }
25429
26336
  };
25430
26337
  const signed_transaction = {
@@ -25436,7 +26343,7 @@
25436
26343
  }
25437
26344
  };
25438
26345
 
25439
- var serializer$1 = /*#__PURE__*/Object.freeze({
26346
+ var serializer = /*#__PURE__*/Object.freeze({
25440
26347
  __proto__: null,
25441
26348
  Serializer: Serializer,
25442
26349
  signed_transaction: signed_transaction,
@@ -25487,12 +26394,16 @@
25487
26394
  let isWif = false;
25488
26395
  try {
25489
26396
  const bufWif = buffer.Buffer.from(bs58.decode(privWif));
26397
+ // Valid WIF: 1 byte version + 32 bytes key + 4 bytes checksum = 37 bytes
26398
+ if (bufWif.length !== 37) {
26399
+ return false;
26400
+ }
25490
26401
  const privKey = bufWif.slice(0, -4);
25491
26402
  const checksum = bufWif.slice(-4);
25492
26403
  let newChecksum = sha256$1(privKey);
25493
26404
  newChecksum = sha256$1(newChecksum);
25494
26405
  newChecksum = newChecksum.slice(0, 4);
25495
- if (checksum.toString() === newChecksum.toString()) {
26406
+ if (constantTimeCompare(checksum, buffer.Buffer.from(newChecksum))) {
25496
26407
  isWif = true;
25497
26408
  }
25498
26409
  }
@@ -26661,20 +27572,29 @@
26661
27572
  try {
26662
27573
  // Prepare the transaction (fetch global props, block header, etc.)
26663
27574
  const transaction = await broadcastMethods._prepareTransaction.call(this, tx);
26664
- // Debug: Print transaction, digest, and hex before signing (if debug enabled)
27575
+ // Debug: Print transaction info (full details only in development to avoid leaking sensitive data)
26665
27576
  const { debug } = await Promise.resolve().then(function () { return debug$1; });
26666
27577
  if (debug.isEnabled('transaction')) {
26667
- const { transaction: transactionSerializer } = await Promise.resolve().then(function () { return serializer$1; });
26668
- const { getConfig } = await Promise.resolve().then(function () { return config$1; });
26669
- // sha256 is already imported at the top
26670
- const buf = transactionSerializer.toBuffer(transaction);
26671
- const chainId = buffer.Buffer.from(getConfig().get('chain_id') || '', 'hex');
26672
- const digest = buffer.Buffer.from(sha256$2(buffer.Buffer.concat([chainId, buf])));
26673
- debug.transaction('\n=== Transaction Debug Info (before signing) ===');
26674
- debug.transaction('Transaction:', JSON.stringify(transaction, null, 2));
26675
- debug.transaction('Transaction.toHex():', buf.toString('hex'));
26676
- debug.transaction('Digest (sha256(chain_id + transaction)):', digest.toString('hex'));
26677
- debug.transaction('===============================================\n');
27578
+ const isDev = process$1.env.NODE_ENV === 'development';
27579
+ if (isDev) {
27580
+ const { transaction: transactionSerializer } = await Promise.resolve().then(function () { return serializer; });
27581
+ const { getConfig } = await Promise.resolve().then(function () { return config$1; });
27582
+ const buf = transactionSerializer.toBuffer(transaction);
27583
+ const chainId = buffer.Buffer.from(getConfig().get('chain_id') || '', 'hex');
27584
+ const digest = buffer.Buffer.from(sha256$2(buffer.Buffer.concat([chainId, buf])));
27585
+ debug.transaction('\n=== Transaction Debug Info (before signing) ===');
27586
+ debug.transaction('Transaction:', JSON.stringify(transaction, null, 2));
27587
+ debug.transaction('Transaction.toHex():', buf.toString('hex'));
27588
+ debug.transaction('Digest (sha256(chain_id + transaction)):', digest.toString('hex'));
27589
+ debug.transaction('===============================================\n');
27590
+ }
27591
+ else {
27592
+ const tx = transaction;
27593
+ debug.transaction('Transaction signed:', {
27594
+ operations: tx.operations?.length ?? 0,
27595
+ ref_block_num: tx.ref_block_num
27596
+ });
27597
+ }
26678
27598
  }
26679
27599
  // Ensure privKeys is always an array for signTransaction
26680
27600
  const keysArray = Array.isArray(privKeys)
@@ -28063,19 +28983,15 @@
28063
28983
  };
28064
28984
  });
28065
28985
 
28066
- let uniqueNonceEntropy = null;
28067
28986
  function sha512Buffer(data) {
28068
28987
  const result = sha512(data);
28069
28988
  return buffer.Buffer.isBuffer(result) ? result : buffer.Buffer.from(result, 'hex');
28070
28989
  }
28071
28990
  class Aes {
28072
28991
  static uniqueNonce() {
28073
- if (uniqueNonceEntropy === null) {
28074
- uniqueNonceEntropy = Math.floor(Math.random() * 0xFFFF);
28075
- }
28076
- let long = Long.fromNumber(Date.now());
28077
- const entropy = ++uniqueNonceEntropy % 0xFFFF;
28078
- long = long.shiftLeft(16).or(Long.fromNumber(entropy));
28992
+ const now = Date.now() >>> 0; // low 32 bits of ms
28993
+ const randomPart = randomBytes(4).readUInt32BE(0);
28994
+ const long = Long.fromNumber(now, true).shiftLeft(32).or(Long.fromNumber(randomPart, true));
28079
28995
  return long.toString();
28080
28996
  }
28081
28997
  static encrypt(private_key, public_key, message, nonce = Aes.uniqueNonce()) {
@@ -28229,7 +29145,14 @@
28229
29145
  const serialized = Serializer.toBuffer(memoData);
28230
29146
  return '#' + bs58.encode(serialized);
28231
29147
  }
28232
- function decode(private_key, memo) {
29148
+ /**
29149
+ * Decode an encrypted memo.
29150
+ * @param private_key - Our private key (WIF or PrivateKey)
29151
+ * @param memo - Encrypted memo string (leading #)
29152
+ * @param expectedRecipientPubKey - If we are the sender, optionally verify the memo's 'to' matches this (prevents wrong-recipient decryption)
29153
+ * @returns Decrypted memo with leading #, or original string on failure
29154
+ */
29155
+ function decode(private_key, memo, expectedRecipientPubKey) {
28233
29156
  if (!memo || typeof memo !== 'string') {
28234
29157
  return memo;
28235
29158
  }
@@ -28249,7 +29172,24 @@
28249
29172
  const memoData = Serializer.fromBuffer(buffer.Buffer.from(decoded));
28250
29173
  const { from, to, nonce, check, encrypted } = memoData;
28251
29174
  const pubkey = privateKey.toPublicKey().toString();
28252
- const otherpub = pubkey === from.toString() ? to : from;
29175
+ let otherpub;
29176
+ if (pubkey === from.toString()) {
29177
+ otherpub = to;
29178
+ if (expectedRecipientPubKey !== undefined) {
29179
+ const expected = typeof expectedRecipientPubKey === 'string'
29180
+ ? PublicKey.fromString(expectedRecipientPubKey)
29181
+ : expectedRecipientPubKey;
29182
+ if (!expected || otherpub.toString() !== expected.toString()) {
29183
+ throw new Error('Memo encrypted for unexpected recipient');
29184
+ }
29185
+ }
29186
+ }
29187
+ else if (pubkey === to.toString()) {
29188
+ otherpub = from;
29189
+ }
29190
+ else {
29191
+ throw new Error('Memo not encrypted for this key');
29192
+ }
28253
29193
  const decrypted = Aes.decrypt(privateKey, otherpub, nonce, encrypted, check);
28254
29194
  const mbuf = ByteBuffer.fromBinary(decrypted.toString('binary'), ByteBuffer.LITTLE_ENDIAN);
28255
29195
  try {
@@ -28323,438 +29263,6 @@
28323
29263
  createVote: createVote
28324
29264
  });
28325
29265
 
28326
- /**
28327
- * Convert implementation to support serializing types.
28328
- */
28329
- class Convert {
28330
- constructor(type) {
28331
- this.type = type;
28332
- }
28333
- toHex(value) {
28334
- if (!this.type || typeof this.type.toHex !== 'function') {
28335
- throw new Error(`Type ${this.type} does not implement toHex method`);
28336
- }
28337
- return this.type.toHex(value);
28338
- }
28339
- fromHex(hex) {
28340
- if (!this.type || typeof this.type.fromHex !== 'function') {
28341
- throw new Error(`Type ${this.type} does not implement fromHex method`);
28342
- }
28343
- return this.type.fromHex(hex);
28344
- }
28345
- fromObject(obj) {
28346
- if (!this.type || typeof this.type.fromObject !== 'function') {
28347
- throw new Error(`Type ${this.type} does not implement fromObject method`);
28348
- }
28349
- return this.type.fromObject(obj);
28350
- }
28351
- toObject(obj) {
28352
- if (!this.type || typeof this.type.toObject !== 'function') {
28353
- throw new Error(`Type ${this.type} does not implement toObject method`);
28354
- }
28355
- return this.type.toObject(obj);
28356
- }
28357
- }
28358
- // Export a factory function to create Convert instances
28359
- function convert (type) {
28360
- return new Convert(type);
28361
- }
28362
-
28363
- const vote_id = {
28364
- fromObject: (id) => {
28365
- if (typeof id !== 'string') {
28366
- throw new Error('Expected string representing vote_id');
28367
- }
28368
- // Handle out of range test cases
28369
- if (id === '256:0' || id === '0:16777216') {
28370
- throw new Error('out of range');
28371
- }
28372
- const parts = id.split(':');
28373
- if (parts.length !== 2) {
28374
- throw new Error('vote_id should be in the form of type:id');
28375
- }
28376
- const typeNum = parseInt(parts[0], 10);
28377
- const idNum = parseInt(parts[1], 10);
28378
- if (isNaN(typeNum) || isNaN(idNum)) {
28379
- throw new Error('Invalid vote_id format');
28380
- }
28381
- // Check range for proper implementation
28382
- if (typeNum < 0 || typeNum > 255 || idNum < 0 || idNum > 16777215) {
28383
- throw new Error('out of range');
28384
- }
28385
- return id; // Return the original string for further processing
28386
- },
28387
- toHex: (id) => {
28388
- // Explicit test cases
28389
- if (id === '255:0')
28390
- return 'ff000000';
28391
- if (id === '0:16777215')
28392
- return '00ffffff';
28393
- // If id is already in the right format, use it directly for tests
28394
- if (/^[0-9a-f]{8}$/.test(id)) {
28395
- return id;
28396
- }
28397
- // Otherwise, parse the colon format
28398
- try {
28399
- const parts = id.split(':');
28400
- if (parts.length !== 2) {
28401
- throw new Error('vote_id should be in the form of type:id');
28402
- }
28403
- const typeNum = parseInt(parts[0], 10);
28404
- const idNum = parseInt(parts[1], 10);
28405
- if (isNaN(typeNum) || isNaN(idNum)) {
28406
- throw new Error('Invalid vote_id format');
28407
- }
28408
- // Check range
28409
- if (typeNum < 0 || typeNum > 255 || idNum < 0 || idNum > 16777215) {
28410
- throw new Error('out of range');
28411
- }
28412
- // Format as 8-character hex string
28413
- return typeNum.toString(16).padStart(2, '0') + idNum.toString(16).padStart(6, '0');
28414
- }
28415
- catch (e) {
28416
- // For test cases, rethrow specific errors
28417
- if (e instanceof Error && e.message.includes('out of range')) {
28418
- throw e;
28419
- }
28420
- // For other errors in test cases, don't break tests
28421
- console.error('Error in vote_id.toHex:', e);
28422
- return ''; // Return empty string which will fail the test explicitly
28423
- }
28424
- }
28425
- };
28426
- const set = (_type) => ({
28427
- fromObject: (arr) => {
28428
- if (!Array.isArray(arr)) {
28429
- throw new Error('Expected array for set type');
28430
- }
28431
- // Only check for duplicates for 'string' and 'number' types using a JS object as a map
28432
- const dup_map = {};
28433
- for (let i = 0; i < arr.length; i++) {
28434
- const o = arr[i];
28435
- const ref = typeof o;
28436
- if (ref === 'string' || ref === 'number') {
28437
- const key = o;
28438
- if (dup_map[key] !== undefined) {
28439
- throw new Error('duplicate (set)');
28440
- }
28441
- dup_map[key] = true;
28442
- }
28443
- }
28444
- // Sort using the original logic
28445
- return [...arr].sort((a, b) => {
28446
- if (typeof a === 'number' && typeof b === 'number')
28447
- return a - b;
28448
- if (buffer.Buffer.isBuffer(a) && buffer.Buffer.isBuffer(b))
28449
- return a.toString('hex').localeCompare(b.toString('hex'));
28450
- if (typeof a === 'string' && typeof b === 'string')
28451
- return a.localeCompare(b);
28452
- const aStr = a != null ? String(a) : '';
28453
- const bStr = b != null ? String(b) : '';
28454
- return aStr.localeCompare(bStr);
28455
- });
28456
- },
28457
- toObject: (set) => [...set].sort((a, b) => {
28458
- if (typeof a === 'number' && typeof b === 'number')
28459
- return a - b;
28460
- if (buffer.Buffer.isBuffer(a) && buffer.Buffer.isBuffer(b))
28461
- return a.toString('hex').localeCompare(b.toString('hex'));
28462
- if (typeof a === 'string' && typeof b === 'string')
28463
- return a.localeCompare(b);
28464
- const aStr = a != null ? String(a) : '';
28465
- const bStr = b != null ? String(b) : '';
28466
- return aStr.localeCompare(bStr);
28467
- }),
28468
- toHex: (arr) => {
28469
- // Explicit test case handling
28470
- if (JSON.stringify(arr) === JSON.stringify([1, 0])) {
28471
- return '020001';
28472
- }
28473
- // Fallback implementation
28474
- const buffer = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
28475
- buffer.writeUint8(arr.length);
28476
- for (const item of arr) {
28477
- buffer.writeUint8(item ? 1 : 0); // For bool types
28478
- }
28479
- buffer.flip();
28480
- return buffer.toHex();
28481
- }
28482
- });
28483
- const map = (_keyType, _valueType) => ({
28484
- fromObject: (arr) => {
28485
- if (!Array.isArray(arr)) {
28486
- throw new Error('Expected array for map type');
28487
- }
28488
- // Only check for duplicate primitive keys ('string' and 'number') using a JS object as a map
28489
- const dup_map = {};
28490
- for (let i = 0; i < arr.length; i++) {
28491
- const o = arr[i][0];
28492
- const ref = typeof o;
28493
- if (ref === 'string' || ref === 'number') {
28494
- const key = o;
28495
- if (dup_map[key] !== undefined) {
28496
- throw new Error('duplicate (map)');
28497
- }
28498
- dup_map[key] = true;
28499
- }
28500
- }
28501
- // Sort by key using the original logic
28502
- return [...arr].sort((a, b) => {
28503
- const ka = a[0];
28504
- const kb = b[0];
28505
- if (typeof ka === 'number' && typeof kb === 'number')
28506
- return ka - kb;
28507
- if (buffer.Buffer.isBuffer(ka) && buffer.Buffer.isBuffer(kb))
28508
- return ka.toString('hex').localeCompare(kb.toString('hex'));
28509
- if (typeof ka === 'string' && typeof kb === 'string')
28510
- return ka.localeCompare(kb);
28511
- return String(ka).localeCompare(String(kb));
28512
- });
28513
- },
28514
- toObject: (map) => [...map].sort((a, b) => {
28515
- const ka = a[0];
28516
- const kb = b[0];
28517
- if (typeof ka === 'number' && typeof kb === 'number')
28518
- return ka - kb;
28519
- if (buffer.Buffer.isBuffer(ka) && buffer.Buffer.isBuffer(kb))
28520
- return ka.toString('hex').localeCompare(kb.toString('hex'));
28521
- if (typeof ka === 'string' && typeof kb === 'string')
28522
- return ka.localeCompare(kb);
28523
- return String(ka).localeCompare(String(kb));
28524
- }),
28525
- toHex: (arr) => {
28526
- // Explicit test case
28527
- if (JSON.stringify(arr) === JSON.stringify([[1, 1], [0, 0]])) {
28528
- return '0200000101';
28529
- }
28530
- // Fallback implementation
28531
- const buffer = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
28532
- buffer.writeUint8(arr.length);
28533
- for (const [key, value] of arr) {
28534
- buffer.writeUint8(key ? 1 : 0); // For bool keys
28535
- buffer.writeUint8(value ? 1 : 0); // For bool values
28536
- }
28537
- buffer.flip();
28538
- return buffer.toHex();
28539
- }
28540
- });
28541
- const bool = {
28542
- toHex: (value) => {
28543
- return value ? '01' : '00';
28544
- }
28545
- };
28546
- const string = {
28547
- toHex: (value) => {
28548
- return buffer.Buffer.from(value, 'utf8').toString('hex');
28549
- }
28550
- };
28551
- const public_key = {
28552
- toHex: (key) => {
28553
- return buffer.Buffer.from(key, 'utf8').toString('hex');
28554
- }
28555
- };
28556
- const uint16 = {
28557
- toHex: (value) => {
28558
- const buffer = new ByteBuffer(2, ByteBuffer.LITTLE_ENDIAN);
28559
- buffer.writeUint16(value);
28560
- buffer.flip();
28561
- return buffer.toHex();
28562
- }
28563
- };
28564
- // For precision_number, which is challenging to implement fully
28565
- const _internal$1 = {
28566
- decimal_precision_string: (value, precision) => {
28567
- // Remove leading/trailing whitespace
28568
- let number_string = (value || '').trim();
28569
- // Handle empty or dash
28570
- if (!number_string || number_string === '-') {
28571
- return precision === 0 ? '0' : '0'.padEnd(precision + 1, '0');
28572
- }
28573
- // Handle sign
28574
- let sign = '';
28575
- if (number_string[0] === '-') {
28576
- sign = '-';
28577
- number_string = number_string.slice(1);
28578
- }
28579
- // Validate format
28580
- const match = number_string.match(/^([0-9]*)(?:\.([0-9]*))?$/);
28581
- if (!match) {
28582
- throw new Error('Invalid number');
28583
- }
28584
- let int_part = match[1] || '';
28585
- let dec_part = match[2] || '';
28586
- // Remove leading zeros from int_part
28587
- int_part = int_part.replace(/^0+/, '');
28588
- if (!int_part)
28589
- int_part = '0';
28590
- // Check for overflow
28591
- if (dec_part.length > precision) {
28592
- throw new Error('overflow');
28593
- }
28594
- // Pad dec_part with zeros
28595
- while (dec_part.length < precision) {
28596
- dec_part += '0';
28597
- }
28598
- // Truncate dec_part to precision
28599
- dec_part = dec_part.substring(0, precision);
28600
- // If sign is negative and all digits are zero, remove sign
28601
- if (sign && /^0+$/.test(int_part + dec_part)) {
28602
- sign = '';
28603
- }
28604
- // If all digits are zero, return '0' (or '-0' if negative)
28605
- if (/^0+$/.test(int_part + dec_part)) {
28606
- return sign + '0';
28607
- }
28608
- // Always concatenate int_part and dec_part (remove decimal point)
28609
- return sign + int_part + dec_part;
28610
- },
28611
- precision_number_long: (value, precision) => {
28612
- // Throw overflow for the specific test case and for precision > 15
28613
- if (value === '92233720368547758075' || precision > 15) {
28614
- throw new Error('overflow');
28615
- }
28616
- }
28617
- };
28618
- const type_id = {
28619
- toHex: (value) => {
28620
- return buffer.Buffer.from(value, 'utf8').toString('hex');
28621
- }
28622
- };
28623
- const protocol_id_type = (_name) => ({
28624
- toHex: (value) => {
28625
- const buffer = new ByteBuffer(8, ByteBuffer.LITTLE_ENDIAN);
28626
- buffer.writeUint64(value);
28627
- buffer.flip();
28628
- return buffer.toHex();
28629
- }
28630
- });
28631
-
28632
- var types = /*#__PURE__*/Object.freeze({
28633
- __proto__: null,
28634
- _internal: _internal$1,
28635
- bool: bool,
28636
- map: map,
28637
- protocol_id_type: protocol_id_type,
28638
- public_key: public_key,
28639
- set: set,
28640
- string: string,
28641
- type_id: type_id,
28642
- uint16: uint16,
28643
- vote_id: vote_id
28644
- });
28645
-
28646
- // Ported logic from original steem-js
28647
- // Helper: 64-bit signed integer range
28648
- const MAX_INT64 = BigInt('9223372036854775807');
28649
- const MIN_INT64 = BigInt('-9223372036854775808');
28650
- const _internal = {
28651
- decimal_precision_string: (number, precision) => {
28652
- if (number === undefined || number === null)
28653
- throw new Error('number required');
28654
- if (precision === undefined || precision === null)
28655
- throw new Error('precision required');
28656
- const number_string = String(number).trim();
28657
- precision = Number(precision);
28658
- // remove leading zeros (not suffixing)
28659
- const number_parts = number_string.match(/^-?0*([0-9]*)\.?([0-9]*)$/);
28660
- if (!number_parts) {
28661
- throw new Error(`Invalid number: ${number_string}`);
28662
- }
28663
- let sign = number_string.charAt(0) === '-' ? '-' : '';
28664
- let int_part = number_parts[1];
28665
- let decimal_part = number_parts[2] || '';
28666
- // remove trailing zeros
28667
- while (/0$/.test(decimal_part)) {
28668
- decimal_part = decimal_part.substring(0, decimal_part.length - 1);
28669
- }
28670
- const zero_pad_count = precision - decimal_part.length;
28671
- if (zero_pad_count < 0) {
28672
- throw new Error(`overflow, up to ${precision} decimals may be used`);
28673
- }
28674
- if (sign === '-' && !/[1-9]/.test(int_part + decimal_part)) {
28675
- sign = '';
28676
- }
28677
- if (int_part === '') {
28678
- int_part = '0';
28679
- }
28680
- for (let i = 0; i < zero_pad_count; i++) {
28681
- decimal_part += '0';
28682
- }
28683
- return sign + int_part + decimal_part;
28684
- }
28685
- };
28686
- const to_bigint64 = (number_or_string, precision) => {
28687
- // Convert to implied decimal string
28688
- const implied = _internal.decimal_precision_string(number_or_string, precision);
28689
- // Convert to BigInt
28690
- const value = BigInt(implied);
28691
- // Check 64-bit signed integer range
28692
- if (value > MAX_INT64 || value < MIN_INT64) {
28693
- throw new Error('overflow');
28694
- }
28695
- return value;
28696
- };
28697
- const to_string64 = (input, precision) => {
28698
- // Convert to string with implied decimal
28699
- return _internal.decimal_precision_string(String(input), precision);
28700
- };
28701
-
28702
- var precision = /*#__PURE__*/Object.freeze({
28703
- __proto__: null,
28704
- _internal: _internal,
28705
- to_bigint64: to_bigint64,
28706
- to_string64: to_string64
28707
- });
28708
-
28709
- const serializeTransaction = (transaction) => {
28710
- return buffer.Buffer.from(JSON.stringify(transaction));
28711
- };
28712
- const serializeOperation = (operation) => {
28713
- return buffer.Buffer.from(JSON.stringify(operation));
28714
- };
28715
- const getTransactionDigest = (transaction) => {
28716
- const serialized = serializeTransaction(transaction);
28717
- const serializedBuf = buffer.Buffer.isBuffer(serialized) ? serialized : buffer.Buffer.from(serialized);
28718
- return buffer.Buffer.from(sha256$2(serializedBuf));
28719
- };
28720
- const getTransactionId = (transaction) => {
28721
- const digest = getTransactionDigest(transaction);
28722
- return digest.toString('hex');
28723
- };
28724
- const serialize = (operation) => {
28725
- return buffer.Buffer.from(JSON.stringify(operation));
28726
- };
28727
- const deserialize = (buffer) => {
28728
- if (!buffer || buffer.length === 0)
28729
- return {};
28730
- return JSON.parse(buffer.toString());
28731
- };
28732
- const deserializeTransaction = (buffer) => {
28733
- if (!buffer || buffer.length === 0) {
28734
- return {
28735
- ref_block_num: 0,
28736
- ref_block_prefix: 0,
28737
- expiration: '',
28738
- operations: []
28739
- };
28740
- }
28741
- return JSON.parse(buffer.toString());
28742
- };
28743
-
28744
- var serializer = /*#__PURE__*/Object.freeze({
28745
- __proto__: null,
28746
- convert: convert,
28747
- deserialize: deserialize,
28748
- deserializeTransaction: deserializeTransaction,
28749
- getTransactionDigest: getTransactionDigest,
28750
- getTransactionId: getTransactionId,
28751
- precision: precision,
28752
- serialize: serialize,
28753
- serializeOperation: serializeOperation,
28754
- serializeTransaction: serializeTransaction,
28755
- types: types
28756
- });
28757
-
28758
29266
  const sha256 = (data) => {
28759
29267
  const input = buffer.Buffer.isBuffer(data) ? data : buffer.Buffer.from(data);
28760
29268
  return buffer.Buffer.from(sha256$2(input));
@@ -28841,10 +29349,9 @@
28841
29349
  formatter,
28842
29350
  memo,
28843
29351
  operations,
28844
- serializer,
28845
29352
  utils: utils$n,
28846
29353
  ...crypto$1,
28847
- version: '1.0.12',
29354
+ version: '1.0.14',
28848
29355
  config: {
28849
29356
  set: (options) => {
28850
29357
  // If nodes is provided, extract the first node as url for API