@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.js CHANGED
@@ -13838,6 +13838,20 @@ class PublicKey {
13838
13838
  const secp256k1$1 = new ellipticExports.ec('secp256k1');
13839
13839
  const G = secp256k1$1.g;
13840
13840
  const n = new BN(secp256k1$1.n.toString());
13841
+ /**
13842
+ * Constant-time buffer comparison to prevent timing attacks.
13843
+ * Returns true only if a.length === b.length and a[i] === b[i] for all i.
13844
+ */
13845
+ function constantTimeCompare(a, b) {
13846
+ if (a.length !== b.length) {
13847
+ return false;
13848
+ }
13849
+ let result = 0;
13850
+ for (let i = 0; i < a.length; i++) {
13851
+ result |= a[i] ^ b[i];
13852
+ }
13853
+ return result === 0;
13854
+ }
13841
13855
  class PrivateKey {
13842
13856
  /**
13843
13857
  * @private see static functions
@@ -13850,11 +13864,8 @@ class PrivateKey {
13850
13864
  if (!Buffer.isBuffer(buf)) {
13851
13865
  throw new Error("Expecting parameter to be a Buffer type");
13852
13866
  }
13853
- if (32 !== buf.length) {
13854
- debug.warn(`WARN: Expecting 32 bytes, instead got ${buf.length}, stack trace:`, new Error().stack);
13855
- }
13856
- if (buf.length === 0) {
13857
- throw new Error("Empty buffer");
13867
+ if (buf.length !== 32) {
13868
+ throw new Error(`Invalid private key buffer: expected 32 bytes, got ${buf.length}`);
13858
13869
  }
13859
13870
  return new PrivateKey(new BN(buf));
13860
13871
  }
@@ -13879,21 +13890,33 @@ class PrivateKey {
13879
13890
  * @return {string} Wallet Import Format (still a secret, Not encrypted)
13880
13891
  */
13881
13892
  static fromWif(private_wif) {
13882
- const private_wif_buffer = Buffer.from(bs58.decode(private_wif));
13893
+ if (!private_wif || typeof private_wif !== 'string') {
13894
+ throw new Error('Invalid WIF: empty or not a string');
13895
+ }
13896
+ let private_wif_buffer;
13897
+ try {
13898
+ private_wif_buffer = Buffer.from(bs58.decode(private_wif));
13899
+ }
13900
+ catch {
13901
+ throw new Error('Invalid WIF: failed to decode base58');
13902
+ }
13903
+ // Valid WIF: 1 byte version + 32 bytes key + 4 bytes checksum = 37 bytes
13904
+ if (private_wif_buffer.length !== 37) {
13905
+ throw new Error(`Invalid WIF: expected 37 bytes, got ${private_wif_buffer.length}`);
13906
+ }
13883
13907
  const version = private_wif_buffer.readUInt8(0);
13884
- if (version !== 0x80)
13885
- throw new Error(`Expected version ${0x80}, instead got ${version}`);
13886
- // checksum includes the version
13887
- const private_key = private_wif_buffer.slice(0, -4);
13888
- const checksum = private_wif_buffer.slice(-4);
13889
- let new_checksum = sha256$1(private_key);
13908
+ if (version !== 0x80) {
13909
+ throw new Error(`Invalid WIF: expected version 0x80, got 0x${version.toString(16)}`);
13910
+ }
13911
+ const private_key = private_wif_buffer.slice(1, 33);
13912
+ const checksum = private_wif_buffer.slice(33);
13913
+ let new_checksum = sha256$1(Buffer.concat([Buffer.from([0x80]), private_key]));
13890
13914
  new_checksum = sha256$1(new_checksum);
13891
13915
  new_checksum = new_checksum.slice(0, 4);
13892
- if (checksum.toString() !== new_checksum.toString()) {
13916
+ if (!constantTimeCompare(checksum, Buffer.from(new_checksum))) {
13893
13917
  throw new Error('Invalid WIF key (checksum miss-match)');
13894
13918
  }
13895
- private_key.writeUInt8(0x80, 0);
13896
- return PrivateKey.fromBuffer(private_key.slice(1));
13919
+ return PrivateKey.fromBuffer(private_key);
13897
13920
  }
13898
13921
  toWif() {
13899
13922
  const private_key = this.toBuffer();
@@ -14272,18 +14295,21 @@ function calcPubKeyRecoveryParam(curve, e, signature, Q) {
14272
14295
  }
14273
14296
  catch (error) {
14274
14297
  // try next value
14275
- console.debug(`Recovery attempt ${i} failed:`, error.message);
14298
+ if (process.env.NODE_ENV === 'development') {
14299
+ console.debug(`Recovery attempt ${i} failed:`, error.message);
14300
+ }
14276
14301
  }
14277
14302
  }
14278
- // Additional debugging
14279
- console.debug('All recovery attempts failed. Signature:', {
14280
- r: signature.r.toString(16),
14281
- s: signature.s.toString(16)
14282
- });
14283
- console.debug('Expected public key:', {
14284
- x: Q.getX().toString(16),
14285
- y: Q.getY().toString(16)
14286
- });
14303
+ if (process.env.NODE_ENV === 'development') {
14304
+ console.debug('All recovery attempts failed. Signature:', {
14305
+ r: signature.r.toString(16),
14306
+ s: signature.s.toString(16)
14307
+ });
14308
+ console.debug('Expected public key:', {
14309
+ x: Q.getX().toString(16),
14310
+ y: Q.getY().toString(16)
14311
+ });
14312
+ }
14287
14313
  throw new Error('Unable to find valid recovery factor');
14288
14314
  }
14289
14315
 
@@ -14335,9 +14361,10 @@ class Signature {
14335
14361
  const d = privKey.d;
14336
14362
  let ecsignature;
14337
14363
  let nonce = 0;
14364
+ const MAX_NONCE_ATTEMPTS = 1000;
14338
14365
  // Match old-steem-js behavior: find canonical signature (lenR === 32 && lenS === 32)
14339
14366
  // Based on C++ is_fc_canonical logic
14340
- while (true) {
14367
+ while (nonce < MAX_NONCE_ATTEMPTS) {
14341
14368
  ecsignature = sign$3(secp256k1, buf_sha256, d, nonce++);
14342
14369
  const rBa = ecsignature.r.toArrayLike(Buffer, 'be', 32);
14343
14370
  const sBa = ecsignature.s.toArrayLike(Buffer, 'be', 32);
@@ -14354,6 +14381,9 @@ class Signature {
14354
14381
  console.debug("WARN: " + nonce + " attempts to find canonical signature");
14355
14382
  }
14356
14383
  }
14384
+ if (nonce >= MAX_NONCE_ATTEMPTS || ecsignature === undefined) {
14385
+ throw new Error('Failed to find canonical signature after maximum attempts');
14386
+ }
14357
14387
  const i = calcPubKeyRecoveryParam(secp256k1, new BN(buf_sha256), ecsignature, privKey.toPublic().Q);
14358
14388
  // Use recovery byte 31-34 (instead of 27-30) to be compatible with dsteem
14359
14389
  // dsteem expects: recovery = byte - 31, so byte = recovery + 31
@@ -14654,7 +14684,11 @@ async function validate(request, verify) {
14654
14684
  if (Number.isNaN(timestamp)) {
14655
14685
  throw new Error('Invalid timestamp');
14656
14686
  }
14657
- if (Date.now() - timestamp > 60 * 1000) {
14687
+ const now = Date.now();
14688
+ const timeDiff = Math.abs(now - timestamp);
14689
+ const SIGNATURE_VALIDITY_MS = 60 * 1000;
14690
+ const MAX_CLOCK_SKEW_MS = 5 * 60 * 1000;
14691
+ if (timeDiff > SIGNATURE_VALIDITY_MS + MAX_CLOCK_SKEW_MS) {
14658
14692
  throw new Error('Signature expired');
14659
14693
  }
14660
14694
  const message = hashMessage(signed.timestamp, signed.account, request.method, signed.params, nonce);
@@ -15629,6 +15663,37 @@ class BaseTransport extends EventEmitter {
15629
15663
  }
15630
15664
 
15631
15665
  // @ts-expect-error: No types for 'retry'
15666
+ /** Detect Node.js for optional undici Agent (custom TLS). */
15667
+ const isNode = typeof process !== 'undefined' &&
15668
+ typeof process.versions === 'object' &&
15669
+ typeof process.versions.node === 'string';
15670
+ /**
15671
+ * Build RequestInit for fetch. In Node when options.httpsOptions is set, inject undici Agent as dispatcher.
15672
+ */
15673
+ async function buildFetchOptions(body, options) {
15674
+ const init = {
15675
+ method: 'POST',
15676
+ headers: {
15677
+ 'Content-Type': 'application/json',
15678
+ 'Accept': 'application/json'
15679
+ },
15680
+ body
15681
+ };
15682
+ if (isNode && options.httpsOptions) {
15683
+ // Node 18+ built-in fetch uses undici; custom TLS via node:undici Agent (built-in, no package)
15684
+ // @ts-expect-error - node:undici is Node built-in, not in @types/node
15685
+ const { Agent } = await import('node:undici');
15686
+ const opts = options.httpsOptions;
15687
+ const agent = new Agent({
15688
+ connect: {
15689
+ rejectUnauthorized: opts.rejectUnauthorized,
15690
+ ca: opts.ca
15691
+ }
15692
+ });
15693
+ init.dispatcher = agent;
15694
+ }
15695
+ return init;
15696
+ }
15632
15697
  /**
15633
15698
  * Extended Error type for JSON-RPC errors
15634
15699
  */
@@ -15648,29 +15713,22 @@ class JsonRpcError extends Error {
15648
15713
  * @param request - The JSON-RPC request object
15649
15714
  * @param fetchMethod - Optional fetch implementation (defaults to global fetch)
15650
15715
  * @param timeoutMs - Request timeout in milliseconds (default: 30000)
15716
+ * @param httpsOptions - Optional TLS options (Node.js only): rejectUnauthorized, ca
15651
15717
  * @returns Promise resolving to the JSON-RPC result
15652
15718
  */
15653
- const jsonRpc = async (url, request, fetchMethod = fetch, timeoutMs = 30000) => {
15719
+ const jsonRpc = async (url, request, fetchMethod = fetch, timeoutMs = 30000, httpsOptions) => {
15654
15720
  const payload = {
15655
15721
  jsonrpc: '2.0',
15656
15722
  ...request
15657
15723
  };
15658
15724
  let timeoutId = null;
15659
- // Create a promise that will reject after the timeout
15660
15725
  const timeoutPromise = new Promise((_, reject) => {
15661
15726
  timeoutId = setTimeout(() => {
15662
15727
  reject(new Error(`Request timeout after ${timeoutMs}ms`));
15663
15728
  }, timeoutMs);
15664
15729
  });
15665
- // Create the fetch promise
15666
- const fetchPromise = fetchMethod(url, {
15667
- method: 'POST',
15668
- headers: {
15669
- 'Content-Type': 'application/json',
15670
- 'Accept': 'application/json'
15671
- },
15672
- body: JSON.stringify(payload)
15673
- })
15730
+ const fetchOptions = await buildFetchOptions(JSON.stringify(payload), { httpsOptions });
15731
+ const fetchPromise = fetchMethod(url, fetchOptions)
15674
15732
  .then(async (res) => {
15675
15733
  if (!res.ok) {
15676
15734
  throw new Error(`HTTP ${res.status}: ${res.statusText}`);
@@ -15721,71 +15779,56 @@ class HttpTransport extends BaseTransport {
15721
15779
  const params = [api, data.method, data.params];
15722
15780
  const isBroadcast = this.isBroadcastOperation(data.method);
15723
15781
  const retryOptions = this.options.retry;
15724
- // Note: timeout handling is done via AbortController in jsonRpc function
15725
- if (!isBroadcast && retryOptions) {
15726
- const operation = typeof retryOptions === 'object' ? retry.operation(retryOptions) : retry.operation();
15727
- operation.attempt((currentAttempt) => {
15728
- fetchMethod(url, {
15729
- method: 'POST',
15730
- body: JSON.stringify({
15731
- jsonrpc: '2.0',
15732
- method: 'call',
15733
- params,
15734
- id
15735
- }),
15736
- headers: { 'Content-Type': 'application/json' },
15737
- })
15738
- .then(async (res) => {
15739
- if (!res.ok) {
15740
- throw new Error(`HTTP ${res.status}: ${res.statusText}`);
15741
- }
15742
- return res.json();
15743
- })
15782
+ const body = JSON.stringify({
15783
+ jsonrpc: '2.0',
15784
+ method: 'call',
15785
+ params,
15786
+ id
15787
+ });
15788
+ const doRequest = (fetchOpts) => fetchMethod(url, fetchOpts)
15789
+ .then(async (res) => {
15790
+ if (!res.ok) {
15791
+ throw new Error(`HTTP ${res.status}: ${res.statusText}`);
15792
+ }
15793
+ return res.json();
15794
+ });
15795
+ const runWithOptions = (fetchOpts) => {
15796
+ if (!isBroadcast && retryOptions) {
15797
+ const operation = typeof retryOptions === 'object' ? retry.operation(retryOptions) : retry.operation();
15798
+ operation.attempt((currentAttempt) => {
15799
+ doRequest(fetchOpts)
15800
+ .then((result) => {
15801
+ if (result.error) {
15802
+ const error = new JsonRpcError(result.error.message || 'JSON-RPC error', result.error.code, result.error.data);
15803
+ callback(error, undefined, currentAttempt);
15804
+ }
15805
+ else {
15806
+ callback(null, result.result, currentAttempt);
15807
+ }
15808
+ }, (error) => {
15809
+ if (operation.retry(error)) {
15810
+ return;
15811
+ }
15812
+ callback(operation.mainError(), undefined, currentAttempt);
15813
+ });
15814
+ });
15815
+ }
15816
+ else {
15817
+ doRequest(fetchOpts)
15744
15818
  .then((result) => {
15745
- // Check for JSON-RPC errors
15746
15819
  if (result.error) {
15747
15820
  const error = new JsonRpcError(result.error.message || 'JSON-RPC error', result.error.code, result.error.data);
15748
- callback(error, undefined, currentAttempt);
15821
+ callback(error, undefined, 1);
15749
15822
  }
15750
15823
  else {
15751
- callback(null, result.result, currentAttempt);
15752
- }
15753
- }, (error) => {
15754
- if (operation.retry(error)) {
15755
- return;
15824
+ callback(null, result.result, 1);
15756
15825
  }
15757
- callback(operation.mainError(), undefined, currentAttempt);
15758
- });
15759
- });
15760
- }
15761
- else {
15762
- fetchMethod(url, {
15763
- method: 'POST',
15764
- body: JSON.stringify({
15765
- jsonrpc: '2.0',
15766
- method: 'call',
15767
- params,
15768
- id
15769
- }),
15770
- headers: { 'Content-Type': 'application/json' }
15771
- })
15772
- .then(async (res) => {
15773
- if (!res.ok) {
15774
- throw new Error(`HTTP ${res.status}: ${res.statusText}`);
15775
- }
15776
- return res.json();
15777
- })
15778
- .then((result) => {
15779
- // Check for JSON-RPC errors
15780
- if (result.error) {
15781
- const error = new JsonRpcError(result.error.message || 'JSON-RPC error', result.error.code, result.error.data);
15782
- callback(error, undefined, 1);
15783
- }
15784
- else {
15785
- callback(null, result.result, 1);
15786
- }
15787
- }, (error) => callback(error instanceof Error ? error : new Error(String(error)), undefined, 1));
15788
- }
15826
+ }, (error) => callback(error instanceof Error ? error : new Error(String(error)), undefined, 1));
15827
+ }
15828
+ };
15829
+ buildFetchOptions(body, this.options)
15830
+ .then(runWithOptions)
15831
+ .catch((err) => callback(err instanceof Error ? err : new Error(String(err)), undefined, 1));
15789
15832
  }
15790
15833
  }
15791
15834
 
@@ -22063,7 +22106,7 @@ if (typeof BigInt === "function") {
22063
22106
  * Serialize a transaction to binary format for Steem blockchain
22064
22107
  * This is a simplified implementation that handles the basic structure
22065
22108
  */
22066
- function serializeTransaction$1(trx) {
22109
+ function serializeTransaction(trx) {
22067
22110
  const bb = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
22068
22111
  const trxObj = trx;
22069
22112
  // Write ref_block_num (uint16)
@@ -22093,7 +22136,7 @@ function serializeTransaction$1(trx) {
22093
22136
  const operations = (Array.isArray(trxObj.operations) ? trxObj.operations : []);
22094
22137
  bb.writeVarint32(operations.length);
22095
22138
  for (const op of operations) {
22096
- serializeOperation$1(bb, op);
22139
+ serializeOperation(bb, op);
22097
22140
  }
22098
22141
  // Write extensions (set of future_extensions, which is void/empty)
22099
22142
  bb.writeVarint32(0); // Empty set
@@ -22122,7 +22165,7 @@ function serializeTransaction$1(trx) {
22122
22165
  /**
22123
22166
  * Serialize an operation to binary format
22124
22167
  */
22125
- function serializeOperation$1(bb, op) {
22168
+ function serializeOperation(bb, op) {
22126
22169
  if (!Array.isArray(op) || op.length !== 2) {
22127
22170
  throw new Error('Operation must be an array of [operation_type, operation_data]');
22128
22171
  }
@@ -22154,9 +22197,45 @@ function getOperationTypeIndex(opType) {
22154
22197
  'account_witness_proxy': 13,
22155
22198
  'pow': 14,
22156
22199
  'custom': 15,
22200
+ 'report_over_production': 16,
22157
22201
  'delete_comment': 17,
22158
22202
  'custom_json': 18,
22159
22203
  'comment_options': 19,
22204
+ 'set_withdraw_vesting_route': 20,
22205
+ 'limit_order_create2': 21,
22206
+ 'claim_account': 22,
22207
+ 'create_claimed_account': 23,
22208
+ 'request_account_recovery': 24,
22209
+ 'recover_account': 25,
22210
+ 'change_recovery_account': 26,
22211
+ 'escrow_transfer': 27,
22212
+ 'escrow_dispute': 28,
22213
+ 'escrow_release': 29,
22214
+ 'pow2': 30,
22215
+ 'escrow_approve': 31,
22216
+ 'transfer_to_savings': 32,
22217
+ 'transfer_from_savings': 33,
22218
+ 'cancel_transfer_from_savings': 34,
22219
+ 'custom_binary': 35,
22220
+ 'decline_voting_rights': 36,
22221
+ 'reset_account': 37,
22222
+ 'set_reset_account': 38,
22223
+ 'claim_reward_balance': 39,
22224
+ 'delegate_vesting_shares': 40,
22225
+ 'account_create_with_delegation': 41,
22226
+ 'witness_set_properties': 42,
22227
+ 'account_update2': 43,
22228
+ 'create_proposal': 44,
22229
+ 'update_proposal_votes': 45,
22230
+ 'remove_proposal': 46,
22231
+ 'claim_reward_balance2': 47,
22232
+ 'fill_convert_request': 48,
22233
+ 'comment_reward': 49,
22234
+ 'liquidity_reward': 50,
22235
+ 'interest': 51,
22236
+ 'fill_vesting_withdraw': 52,
22237
+ 'fill_order': 53,
22238
+ 'fill_transfer_from_savings': 54,
22160
22239
  };
22161
22240
  const index = opMap[opType];
22162
22241
  if (index === undefined) {
@@ -22181,6 +22260,135 @@ function serializeOperationData(bb, opType, opData) {
22181
22260
  case 'account_create':
22182
22261
  serializeAccountCreate(bb, opData);
22183
22262
  break;
22263
+ case 'account_update':
22264
+ serializeAccountUpdate(bb, opData);
22265
+ break;
22266
+ case 'account_create_with_delegation':
22267
+ serializeAccountCreateWithDelegation(bb, opData);
22268
+ break;
22269
+ case 'create_claimed_account':
22270
+ serializeCreateClaimedAccount(bb, opData);
22271
+ break;
22272
+ case 'account_update2':
22273
+ serializeAccountUpdate2(bb, opData);
22274
+ break;
22275
+ case 'request_account_recovery':
22276
+ serializeRequestAccountRecovery(bb, opData);
22277
+ break;
22278
+ case 'recover_account':
22279
+ serializeRecoverAccount(bb, opData);
22280
+ break;
22281
+ case 'change_recovery_account':
22282
+ serializeChangeRecoveryAccount(bb, opData);
22283
+ break;
22284
+ case 'reset_account':
22285
+ serializeResetAccount(bb, opData);
22286
+ break;
22287
+ case 'set_reset_account':
22288
+ serializeSetResetAccount(bb, opData);
22289
+ break;
22290
+ case 'decline_voting_rights':
22291
+ serializeDeclineVotingRights(bb, opData);
22292
+ break;
22293
+ case 'transfer_to_vesting':
22294
+ serializeTransferToVesting(bb, opData);
22295
+ break;
22296
+ case 'withdraw_vesting':
22297
+ serializeWithdrawVesting(bb, opData);
22298
+ break;
22299
+ case 'set_withdraw_vesting_route':
22300
+ serializeSetWithdrawVestingRoute(bb, opData);
22301
+ break;
22302
+ case 'transfer_to_savings':
22303
+ serializeTransferToSavings(bb, opData);
22304
+ break;
22305
+ case 'transfer_from_savings':
22306
+ serializeTransferFromSavings(bb, opData);
22307
+ break;
22308
+ case 'cancel_transfer_from_savings':
22309
+ serializeCancelTransferFromSavings(bb, opData);
22310
+ break;
22311
+ case 'limit_order_create':
22312
+ serializeLimitOrderCreate(bb, opData);
22313
+ break;
22314
+ case 'limit_order_create2':
22315
+ serializeLimitOrderCreate2(bb, opData);
22316
+ break;
22317
+ case 'limit_order_cancel':
22318
+ serializeLimitOrderCancel(bb, opData);
22319
+ break;
22320
+ case 'feed_publish':
22321
+ serializeFeedPublish(bb, opData);
22322
+ break;
22323
+ case 'convert':
22324
+ serializeConvert(bb, opData);
22325
+ break;
22326
+ case 'fill_order':
22327
+ serializeFillOrder(bb, opData);
22328
+ break;
22329
+ case 'escrow_transfer':
22330
+ serializeEscrowTransfer(bb, opData);
22331
+ break;
22332
+ case 'escrow_dispute':
22333
+ serializeEscrowDispute(bb, opData);
22334
+ break;
22335
+ case 'escrow_release':
22336
+ serializeEscrowRelease(bb, opData);
22337
+ break;
22338
+ case 'escrow_approve':
22339
+ serializeEscrowApprove(bb, opData);
22340
+ break;
22341
+ case 'claim_reward_balance':
22342
+ serializeClaimRewardBalance(bb, opData);
22343
+ break;
22344
+ case 'claim_reward_balance2':
22345
+ serializeClaimRewardBalance2(bb, opData);
22346
+ break;
22347
+ case 'comment_reward':
22348
+ serializeCommentReward(bb, opData);
22349
+ break;
22350
+ case 'liquidity_reward':
22351
+ serializeLiquidityReward(bb, opData);
22352
+ break;
22353
+ case 'interest':
22354
+ serializeInterest(bb, opData);
22355
+ break;
22356
+ case 'fill_vesting_withdraw':
22357
+ serializeFillVestingWithdraw(bb, opData);
22358
+ break;
22359
+ case 'fill_convert_request':
22360
+ serializeFillConvertRequest(bb, opData);
22361
+ break;
22362
+ case 'fill_transfer_from_savings':
22363
+ serializeFillTransferFromSavings(bb, opData);
22364
+ break;
22365
+ case 'pow':
22366
+ serializePow(bb, opData);
22367
+ break;
22368
+ case 'pow2':
22369
+ serializePow2(bb, opData);
22370
+ break;
22371
+ case 'witness_update':
22372
+ serializeWitnessUpdate(bb, opData);
22373
+ break;
22374
+ case 'witness_set_properties':
22375
+ serializeWitnessSetProperties(bb, opData);
22376
+ break;
22377
+ case 'account_witness_vote':
22378
+ serializeAccountWitnessVote(bb, opData);
22379
+ break;
22380
+ case 'account_witness_proxy':
22381
+ serializeAccountWitnessProxy(bb, opData);
22382
+ break;
22383
+ case 'custom':
22384
+ serializeCustom(bb, opData);
22385
+ break;
22386
+ case 'custom_binary':
22387
+ serializeCustomBinary(bb, opData);
22388
+ break;
22389
+ case 'comment_options':
22390
+ serializeCommentOptions(bb, opData);
22391
+ break;
22184
22392
  case 'custom_json':
22185
22393
  serializeCustomJson(bb, opData);
22186
22394
  break;
@@ -22251,143 +22459,843 @@ function serializeAccountCreate(bb, data) {
22251
22459
  writeString(bb, String(dataObj.json_metadata || ''));
22252
22460
  }
22253
22461
  /**
22254
- * Serialize custom_json operation
22462
+ * Serialize account_update operation.
22463
+ * Format: account, optional owner (1 byte + authority?), optional active, optional posting, memo_key, json_metadata.
22255
22464
  */
22256
- function serializeCustomJson(bb, data) {
22465
+ function serializeAccountUpdate(bb, data) {
22257
22466
  const dataObj = data;
22258
- // Serialize required_auths (flat_set<account_name_type>)
22259
- // Set serialization: varint32 length, then each element
22260
- const requiredAuths = Array.isArray(dataObj.required_auths)
22261
- ? dataObj.required_auths.slice().sort()
22262
- : [];
22263
- bb.writeVarint32(requiredAuths.length);
22264
- for (const account of requiredAuths) {
22265
- writeString(bb, String(account));
22467
+ writeString(bb, String(dataObj.account || ''));
22468
+ // Optional authorities: 0 = not present, 1 = present then serialize authority
22469
+ if (dataObj.owner != null && dataObj.owner !== '') {
22470
+ bb.writeUint8(1);
22471
+ serializeAuthority(bb, typeof dataObj.owner === 'object' ? dataObj.owner : { weight_threshold: 1, account_auths: [], key_auths: [] });
22266
22472
  }
22267
- // Serialize required_posting_auths (flat_set<account_name_type>)
22268
- const requiredPostingAuths = Array.isArray(dataObj.required_posting_auths)
22269
- ? dataObj.required_posting_auths.slice().sort()
22270
- : [];
22271
- bb.writeVarint32(requiredPostingAuths.length);
22272
- for (const account of requiredPostingAuths) {
22273
- writeString(bb, String(account));
22473
+ else {
22474
+ bb.writeUint8(0);
22274
22475
  }
22275
- // Serialize id (string)
22276
- writeString(bb, String(dataObj.id || ''));
22277
- // Serialize json (string)
22278
- writeString(bb, String(dataObj.json || '{}'));
22476
+ if (dataObj.active != null && dataObj.active !== '') {
22477
+ bb.writeUint8(1);
22478
+ serializeAuthority(bb, typeof dataObj.active === 'object' ? dataObj.active : { weight_threshold: 1, account_auths: [], key_auths: [] });
22479
+ }
22480
+ else {
22481
+ bb.writeUint8(0);
22482
+ }
22483
+ if (dataObj.posting != null && dataObj.posting !== '') {
22484
+ bb.writeUint8(1);
22485
+ serializeAuthority(bb, typeof dataObj.posting === 'object' ? dataObj.posting : { weight_threshold: 1, account_auths: [], key_auths: [] });
22486
+ }
22487
+ else {
22488
+ bb.writeUint8(0);
22489
+ }
22490
+ // memo_key (public key, required)
22491
+ if (typeof dataObj.memo_key === 'string') {
22492
+ const pubKey = PublicKey.fromStringOrThrow(dataObj.memo_key);
22493
+ bb.append(pubKey.toBuffer());
22494
+ }
22495
+ else if (Buffer.isBuffer(dataObj.memo_key)) {
22496
+ bb.append(dataObj.memo_key);
22497
+ }
22498
+ else if (dataObj.memo_key && typeof dataObj.memo_key.toBuffer === 'function') {
22499
+ bb.append(dataObj.memo_key.toBuffer());
22500
+ }
22501
+ else {
22502
+ throw new Error('Invalid memo_key format');
22503
+ }
22504
+ writeString(bb, typeof dataObj.json_metadata === 'string'
22505
+ ? dataObj.json_metadata
22506
+ : dataObj.json_metadata != null
22507
+ ? JSON.stringify(dataObj.json_metadata)
22508
+ : '');
22279
22509
  }
22280
22510
  /**
22281
- * Serialize Authority
22511
+ * Serialize account_create_with_delegation operation.
22512
+ * Fields (see FC_REFLECT): fee, delegation, creator, new_account_name,
22513
+ * owner, active, posting, memo_key, json_metadata, extensions.
22282
22514
  */
22283
- function serializeAuthority(bb, auth) {
22284
- const authObj = auth;
22285
- bb.writeUint32(authObj.weight_threshold || 1);
22286
- // Account auths (map<string, uint16>)
22287
- const accountAuths = (Array.isArray(authObj.account_auths) ? authObj.account_auths : []);
22288
- // Maps in Steem serialization are sorted by key
22289
- const accountAuthsArray = accountAuths;
22290
- accountAuthsArray.sort((a, b) => {
22291
- const aKey = Array.isArray(a) && a[0] ? String(a[0]) : '';
22292
- const bKey = Array.isArray(b) && b[0] ? String(b[0]) : '';
22293
- return aKey.localeCompare(bKey);
22294
- });
22295
- bb.writeVarint32(accountAuths.length);
22296
- for (const authEntry of accountAuths) {
22297
- if (Array.isArray(authEntry) && authEntry.length >= 2) {
22298
- writeString(bb, String(authEntry[0]));
22299
- bb.writeUint16(authEntry[1]);
22300
- }
22301
- }
22302
- // Key auths (map<public_key, uint16>)
22303
- const keyAuths = (Array.isArray(authObj.key_auths) ? authObj.key_auths : []);
22304
- // Maps in Steem serialization are sorted by key (public key string)
22305
- // But serialized as bytes. Usually sorting by string representation of public key works.
22306
- const keyAuthsArray = keyAuths;
22307
- keyAuthsArray.sort((a, b) => {
22308
- const aKey = Array.isArray(a) && a[0] ? String(a[0]) : '';
22309
- const bKey = Array.isArray(b) && b[0] ? String(b[0]) : '';
22310
- return aKey.localeCompare(bKey);
22311
- });
22312
- bb.writeVarint32(keyAuths.length);
22313
- for (const keyAuth of keyAuths) {
22314
- if (Array.isArray(keyAuth) && keyAuth.length >= 2) {
22315
- const keyStr = String(keyAuth[0]);
22316
- const weight = keyAuth[1];
22317
- const pubKey = PublicKey.fromStringOrThrow(keyStr);
22318
- bb.append(pubKey.toBuffer());
22319
- bb.writeUint16(weight);
22320
- }
22321
- }
22515
+ function serializeAccountCreateWithDelegation(bb, data) {
22516
+ const dataObj = data;
22517
+ serializeAsset(bb, String(dataObj.fee || '0.000 STEEM'));
22518
+ serializeAsset(bb, String(dataObj.delegation || '0.000 VESTS'));
22519
+ writeString(bb, String(dataObj.creator || ''));
22520
+ writeString(bb, String(dataObj.new_account_name || ''));
22521
+ serializeAuthority(bb, dataObj.owner);
22522
+ serializeAuthority(bb, dataObj.active);
22523
+ serializeAuthority(bb, dataObj.posting);
22524
+ const memoKey = String(dataObj.memo_key || '');
22525
+ const pubKey = PublicKey.fromStringOrThrow(memoKey);
22526
+ bb.append(pubKey.toBuffer());
22527
+ writeString(bb, String(dataObj.json_metadata || ''));
22528
+ serializeExtensions(bb, dataObj.extensions);
22322
22529
  }
22323
22530
  /**
22324
- * Serialize asset (simplified)
22531
+ * Serialize create_claimed_account operation.
22532
+ * Fields: creator, new_account_name, owner, active, posting,
22533
+ * memo_key, json_metadata, extensions.
22325
22534
  */
22326
- function serializeAsset(bb, amount) {
22327
- const parts = amount.split(' ');
22328
- const valueStr = parts[0] || '0.000';
22329
- const symbol = parts[1] || 'STEEM';
22330
- const [intPart, decPart = ''] = valueStr.split('.');
22331
- const precision = decPart.length;
22332
- const amountValue = parseInt(intPart + decPart.padEnd(precision, '0'), 10) || 0;
22333
- // ByteBuffer can accept number directly for small values
22334
- bb.writeInt64(amountValue);
22335
- bb.writeUint8(precision);
22336
- const symbolBytes = Buffer.from(symbol, 'utf8');
22337
- bb.append(symbolBytes);
22338
- for (let i = symbolBytes.length; i < 7; i++) {
22339
- bb.writeUint8(0);
22340
- }
22535
+ function serializeCreateClaimedAccount(bb, data) {
22536
+ const dataObj = data;
22537
+ writeString(bb, String(dataObj.creator || ''));
22538
+ writeString(bb, String(dataObj.new_account_name || ''));
22539
+ serializeAuthority(bb, dataObj.owner);
22540
+ serializeAuthority(bb, dataObj.active);
22541
+ serializeAuthority(bb, dataObj.posting);
22542
+ const memoKey = String(dataObj.memo_key || '');
22543
+ const pubKey = PublicKey.fromStringOrThrow(memoKey);
22544
+ bb.append(pubKey.toBuffer());
22545
+ writeString(bb, String(dataObj.json_metadata || ''));
22546
+ serializeExtensions(bb, dataObj.extensions);
22341
22547
  }
22342
22548
  /**
22343
- * Write a string using ByteBuffer's writeVString method
22549
+ * Serialize account_update2 operation.
22550
+ * Fields: account, owner, active, posting, memo_key,
22551
+ * json_metadata, posting_json_metadata, extensions.
22344
22552
  */
22345
- function writeString(bb, str) {
22346
- bb.writeVString(str);
22553
+ function serializeAccountUpdate2(bb, data) {
22554
+ const dataObj = data;
22555
+ writeString(bb, String(dataObj.account || ''));
22556
+ serializeAuthority(bb, dataObj.owner);
22557
+ serializeAuthority(bb, dataObj.active);
22558
+ serializeAuthority(bb, dataObj.posting);
22559
+ const memoKey = String(dataObj.memo_key || '');
22560
+ const pubKey = PublicKey.fromStringOrThrow(memoKey);
22561
+ bb.append(pubKey.toBuffer());
22562
+ writeString(bb, String(dataObj.json_metadata || ''));
22563
+ writeString(bb, String(dataObj.posting_json_metadata || ''));
22564
+ serializeExtensions(bb, dataObj.extensions);
22347
22565
  }
22348
-
22349
- class Serializer {
22350
- static fromBuffer(buffer) {
22351
- const bb = ByteBuffer.fromBinary(buffer.toString('binary'), ByteBuffer.LITTLE_ENDIAN);
22352
- // Read public keys
22353
- const fromKey = PublicKey.fromBuffer(bb.readBytes(33).toBuffer());
22354
- const toKey = PublicKey.fromBuffer(bb.readBytes(33).toBuffer());
22355
- // Read nonce (uint64)
22356
- const nonce = bb.readUint64().toString();
22357
- // Read checksum (uint32)
22358
- const check = bb.readUint32();
22359
- // Read encrypted data
22360
- const encryptedLength = bb.readVarint32();
22361
- const encrypted = bb.readBytes(encryptedLength).toString('hex');
22362
- return {
22363
- from: fromKey,
22364
- to: toKey,
22365
- nonce,
22366
- check,
22367
- encrypted
22368
- };
22369
- }
22370
- static toBuffer(memo) {
22371
- const bb = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
22372
- // Write public keys
22373
- bb.append(memo.from.toBuffer());
22374
- bb.append(memo.to.toBuffer());
22375
- // Write nonce (uint64) - handle both string and number
22376
- let nonceLong;
22377
- if (typeof memo.nonce === 'string') {
22378
- // Use Long.fromString with unsigned flag for large numbers
22379
- try {
22566
+ /**
22567
+ * Serialize request_account_recovery operation.
22568
+ * Fields: recovery_account, account_to_recover, new_owner_authority, extensions.
22569
+ */
22570
+ function serializeRequestAccountRecovery(bb, data) {
22571
+ const dataObj = data;
22572
+ writeString(bb, String(dataObj.recovery_account || ''));
22573
+ writeString(bb, String(dataObj.account_to_recover || ''));
22574
+ serializeAuthority(bb, dataObj.new_owner_authority);
22575
+ serializeExtensions(bb, dataObj.extensions);
22576
+ }
22577
+ /**
22578
+ * Serialize recover_account operation.
22579
+ * Fields: account_to_recover, new_owner_authority, recent_owner_authority, extensions.
22580
+ */
22581
+ function serializeRecoverAccount(bb, data) {
22582
+ const dataObj = data;
22583
+ writeString(bb, String(dataObj.account_to_recover || ''));
22584
+ serializeAuthority(bb, dataObj.new_owner_authority);
22585
+ serializeAuthority(bb, dataObj.recent_owner_authority);
22586
+ serializeExtensions(bb, dataObj.extensions);
22587
+ }
22588
+ /**
22589
+ * Serialize change_recovery_account operation.
22590
+ * Fields: account_to_recover, new_recovery_account, extensions.
22591
+ */
22592
+ function serializeChangeRecoveryAccount(bb, data) {
22593
+ const dataObj = data;
22594
+ writeString(bb, String(dataObj.account_to_recover || ''));
22595
+ writeString(bb, String(dataObj.new_recovery_account || ''));
22596
+ serializeExtensions(bb, dataObj.extensions);
22597
+ }
22598
+ /**
22599
+ * Serialize reset_account operation.
22600
+ * Fields: reset_account, account_to_reset, new_owner_authority.
22601
+ */
22602
+ function serializeResetAccount(bb, data) {
22603
+ const dataObj = data;
22604
+ writeString(bb, String(dataObj.reset_account || ''));
22605
+ writeString(bb, String(dataObj.account_to_reset || ''));
22606
+ serializeAuthority(bb, dataObj.new_owner_authority);
22607
+ }
22608
+ /**
22609
+ * Serialize set_reset_account operation.
22610
+ * Fields: account, reset_account.
22611
+ */
22612
+ function serializeSetResetAccount(bb, data) {
22613
+ const dataObj = data;
22614
+ writeString(bb, String(dataObj.account || ''));
22615
+ writeString(bb, String(dataObj.reset_account || ''));
22616
+ }
22617
+ /**
22618
+ * Serialize decline_voting_rights operation.
22619
+ * Fields: account, decline.
22620
+ */
22621
+ function serializeDeclineVotingRights(bb, data) {
22622
+ const dataObj = data;
22623
+ writeString(bb, String(dataObj.account || ''));
22624
+ serializeBool(bb, dataObj.decline);
22625
+ }
22626
+ /**
22627
+ * Serialize transfer_to_vesting operation.
22628
+ * Fields: from, to, amount.
22629
+ */
22630
+ function serializeTransferToVesting(bb, data) {
22631
+ const dataObj = data;
22632
+ writeString(bb, String(dataObj.from || ''));
22633
+ writeString(bb, String(dataObj.to || ''));
22634
+ serializeAsset(bb, String(dataObj.amount || '0.000 STEEM'));
22635
+ }
22636
+ /**
22637
+ * Serialize withdraw_vesting operation.
22638
+ * Fields: account, vesting_shares.
22639
+ */
22640
+ function serializeWithdrawVesting(bb, data) {
22641
+ const dataObj = data;
22642
+ writeString(bb, String(dataObj.account || ''));
22643
+ serializeAsset(bb, String(dataObj.vesting_shares || '0.000 VESTS'));
22644
+ }
22645
+ /**
22646
+ * Serialize set_withdraw_vesting_route operation.
22647
+ * Fields: from_account, to_account, percent, auto_vest.
22648
+ */
22649
+ function serializeSetWithdrawVestingRoute(bb, data) {
22650
+ const dataObj = data;
22651
+ writeString(bb, String(dataObj.from_account || ''));
22652
+ writeString(bb, String(dataObj.to_account || ''));
22653
+ // percent is uint16
22654
+ bb.writeUint16(dataObj.percent ?? 0);
22655
+ serializeBool(bb, dataObj.auto_vest);
22656
+ }
22657
+ /**
22658
+ * Serialize transfer_to_savings operation.
22659
+ * Fields: from, to, amount, memo.
22660
+ */
22661
+ function serializeTransferToSavings(bb, data) {
22662
+ const dataObj = data;
22663
+ writeString(bb, String(dataObj.from || ''));
22664
+ writeString(bb, String(dataObj.to || ''));
22665
+ serializeAsset(bb, String(dataObj.amount || '0.000 STEEM'));
22666
+ writeString(bb, String(dataObj.memo || ''));
22667
+ }
22668
+ /**
22669
+ * Serialize transfer_from_savings operation.
22670
+ * Fields: from, request_id, to, amount, memo.
22671
+ */
22672
+ function serializeTransferFromSavings(bb, data) {
22673
+ const dataObj = data;
22674
+ writeString(bb, String(dataObj.from || ''));
22675
+ bb.writeUint32(dataObj.request_id ?? dataObj.requestID ?? 0);
22676
+ writeString(bb, String(dataObj.to || ''));
22677
+ serializeAsset(bb, String(dataObj.amount || '0.000 STEEM'));
22678
+ writeString(bb, String(dataObj.memo || ''));
22679
+ }
22680
+ /**
22681
+ * Serialize cancel_transfer_from_savings operation.
22682
+ * Fields: from, request_id.
22683
+ */
22684
+ function serializeCancelTransferFromSavings(bb, data) {
22685
+ const dataObj = data;
22686
+ writeString(bb, String(dataObj.from || ''));
22687
+ bb.writeUint32(dataObj.request_id ?? dataObj.requestID ?? 0);
22688
+ }
22689
+ /**
22690
+ * Serialize limit_order_create operation.
22691
+ * Fields: owner, orderid, amount_to_sell, min_to_receive, fill_or_kill, expiration.
22692
+ */
22693
+ function serializeLimitOrderCreate(bb, data) {
22694
+ const dataObj = data;
22695
+ writeString(bb, String(dataObj.owner || ''));
22696
+ bb.writeUint32(dataObj.orderid ?? 0);
22697
+ serializeAsset(bb, String(dataObj.amount_to_sell || '0.000 STEEM'));
22698
+ serializeAsset(bb, String(dataObj.min_to_receive || '0.000 STEEM'));
22699
+ serializeBool(bb, dataObj.fill_or_kill);
22700
+ serializeTimePointSec(bb, dataObj.expiration);
22701
+ }
22702
+ /**
22703
+ * Serialize limit_order_create2 operation.
22704
+ * Fields: owner, orderid, amount_to_sell, exchange_rate{base, quote}, fill_or_kill, expiration.
22705
+ */
22706
+ function serializeLimitOrderCreate2(bb, data) {
22707
+ const dataObj = data;
22708
+ writeString(bb, String(dataObj.owner || ''));
22709
+ bb.writeUint32(dataObj.orderid ?? 0);
22710
+ serializeAsset(bb, String(dataObj.amount_to_sell || '0.000 STEEM'));
22711
+ const rate = (dataObj.exchange_rate ?? dataObj.exchangeRate);
22712
+ const base = rate?.base ?? '0.000 STEEM';
22713
+ const quote = rate?.quote ?? '0.000 SBD';
22714
+ serializeAsset(bb, String(base));
22715
+ serializeAsset(bb, String(quote));
22716
+ serializeBool(bb, dataObj.fill_or_kill);
22717
+ serializeTimePointSec(bb, dataObj.expiration);
22718
+ }
22719
+ /**
22720
+ * Serialize limit_order_cancel operation.
22721
+ * Fields: owner, orderid.
22722
+ */
22723
+ function serializeLimitOrderCancel(bb, data) {
22724
+ const dataObj = data;
22725
+ writeString(bb, String(dataObj.owner || ''));
22726
+ bb.writeUint32(dataObj.orderid ?? 0);
22727
+ }
22728
+ /**
22729
+ * Serialize feed_publish operation.
22730
+ * Fields: publisher, exchange_rate{base, quote}.
22731
+ */
22732
+ function serializeFeedPublish(bb, data) {
22733
+ const dataObj = data;
22734
+ writeString(bb, String(dataObj.publisher || ''));
22735
+ const rate = (dataObj.exchange_rate ?? dataObj.exchangeRate);
22736
+ const base = rate?.base ?? '0.000 STEEM';
22737
+ const quote = rate?.quote ?? '0.000 SBD';
22738
+ serializeAsset(bb, String(base));
22739
+ serializeAsset(bb, String(quote));
22740
+ }
22741
+ /**
22742
+ * Serialize convert operation.
22743
+ * Fields: owner, requestid, amount.
22744
+ */
22745
+ function serializeConvert(bb, data) {
22746
+ const dataObj = data;
22747
+ writeString(bb, String(dataObj.owner || ''));
22748
+ bb.writeUint32(dataObj.requestid ?? dataObj.request_id ?? 0);
22749
+ serializeAsset(bb, String(dataObj.amount || '0.000 STEEM'));
22750
+ }
22751
+ /**
22752
+ * Serialize fill_order operation (virtual).
22753
+ * Fields: current_owner, current_orderid, current_pays,
22754
+ * open_owner, open_orderid, open_pays.
22755
+ */
22756
+ function serializeFillOrder(bb, data) {
22757
+ const dataObj = data;
22758
+ writeString(bb, String(dataObj.current_owner || ''));
22759
+ bb.writeUint32(dataObj.current_orderid ?? 0);
22760
+ serializeAsset(bb, String(dataObj.current_pays || '0.000 STEEM'));
22761
+ writeString(bb, String(dataObj.open_owner || ''));
22762
+ bb.writeUint32(dataObj.open_orderid ?? 0);
22763
+ serializeAsset(bb, String(dataObj.open_pays || '0.000 STEEM'));
22764
+ }
22765
+ /**
22766
+ * Serialize escrow_transfer operation.
22767
+ * Fields: from, to, sbd_amount, steem_amount, escrow_id, agent,
22768
+ * fee, json_meta, ratification_deadline, escrow_expiration.
22769
+ */
22770
+ function serializeEscrowTransfer(bb, data) {
22771
+ const dataObj = data;
22772
+ writeString(bb, String(dataObj.from || ''));
22773
+ writeString(bb, String(dataObj.to || ''));
22774
+ serializeAsset(bb, String(dataObj.sbd_amount || '0.000 SBD'));
22775
+ serializeAsset(bb, String(dataObj.steem_amount || '0.000 STEEM'));
22776
+ bb.writeUint32(dataObj.escrow_id ?? 0);
22777
+ writeString(bb, String(dataObj.agent || ''));
22778
+ serializeAsset(bb, String(dataObj.fee || '0.000 STEEM'));
22779
+ writeString(bb, String(dataObj.json_meta || ''));
22780
+ serializeTimePointSec(bb, dataObj.ratification_deadline);
22781
+ serializeTimePointSec(bb, dataObj.escrow_expiration);
22782
+ }
22783
+ /**
22784
+ * Serialize escrow_dispute operation.
22785
+ * Fields: from, to, who, escrow_id.
22786
+ */
22787
+ function serializeEscrowDispute(bb, data) {
22788
+ const dataObj = data;
22789
+ writeString(bb, String(dataObj.from || ''));
22790
+ writeString(bb, String(dataObj.to || ''));
22791
+ writeString(bb, String(dataObj.who || ''));
22792
+ bb.writeUint32(dataObj.escrow_id ?? 0);
22793
+ }
22794
+ /**
22795
+ * Serialize escrow_release operation.
22796
+ * Fields: from, to, who, escrow_id, sbd_amount, steem_amount.
22797
+ */
22798
+ function serializeEscrowRelease(bb, data) {
22799
+ const dataObj = data;
22800
+ writeString(bb, String(dataObj.from || ''));
22801
+ writeString(bb, String(dataObj.to || ''));
22802
+ writeString(bb, String(dataObj.who || ''));
22803
+ bb.writeUint32(dataObj.escrow_id ?? 0);
22804
+ serializeAsset(bb, String(dataObj.sbd_amount || '0.000 SBD'));
22805
+ serializeAsset(bb, String(dataObj.steem_amount || '0.000 STEEM'));
22806
+ }
22807
+ /**
22808
+ * Serialize escrow_approve operation.
22809
+ * Fields: from, to, agent, who, escrow_id, approve.
22810
+ */
22811
+ function serializeEscrowApprove(bb, data) {
22812
+ const dataObj = data;
22813
+ writeString(bb, String(dataObj.from || ''));
22814
+ writeString(bb, String(dataObj.to || ''));
22815
+ writeString(bb, String(dataObj.agent || ''));
22816
+ writeString(bb, String(dataObj.who || ''));
22817
+ bb.writeUint32(dataObj.escrow_id ?? 0);
22818
+ serializeBool(bb, dataObj.approve);
22819
+ }
22820
+ /**
22821
+ * Serialize claim_reward_balance operation.
22822
+ * Fields: account, reward_steem, reward_sbd, reward_vests.
22823
+ */
22824
+ function serializeClaimRewardBalance(bb, data) {
22825
+ const dataObj = data;
22826
+ writeString(bb, String(dataObj.account || ''));
22827
+ serializeAsset(bb, String(dataObj.reward_steem || '0.000 STEEM'));
22828
+ serializeAsset(bb, String(dataObj.reward_sbd || '0.000 SBD'));
22829
+ serializeAsset(bb, String(dataObj.reward_vests || '0.000000 VESTS'));
22830
+ }
22831
+ /**
22832
+ * Serialize claim_reward_balance2 operation.
22833
+ * Fields: account, extensions, reward_tokens (array of asset strings).
22834
+ */
22835
+ function serializeClaimRewardBalance2(bb, data) {
22836
+ const dataObj = data;
22837
+ writeString(bb, String(dataObj.account || ''));
22838
+ serializeExtensions(bb, dataObj.extensions);
22839
+ const tokens = Array.isArray(dataObj.reward_tokens) ? dataObj.reward_tokens : [];
22840
+ bb.writeVarint32(tokens.length);
22841
+ for (const tok of tokens) {
22842
+ serializeAsset(bb, typeof tok === 'string' ? tok : String(tok));
22843
+ }
22844
+ }
22845
+ /**
22846
+ * Serialize comment_reward operation.
22847
+ * Fields: author, permlink, payout.
22848
+ */
22849
+ function serializeCommentReward(bb, data) {
22850
+ const dataObj = data;
22851
+ writeString(bb, String(dataObj.author || ''));
22852
+ writeString(bb, String(dataObj.permlink || ''));
22853
+ serializeAsset(bb, String(dataObj.payout || '0.000 STEEM'));
22854
+ }
22855
+ /**
22856
+ * Serialize liquidity_reward operation.
22857
+ * Fields: owner, payout.
22858
+ */
22859
+ function serializeLiquidityReward(bb, data) {
22860
+ const dataObj = data;
22861
+ writeString(bb, String(dataObj.owner || ''));
22862
+ serializeAsset(bb, String(dataObj.payout || '0.000 STEEM'));
22863
+ }
22864
+ /**
22865
+ * Serialize interest operation.
22866
+ * Fields: owner, interest.
22867
+ */
22868
+ function serializeInterest(bb, data) {
22869
+ const dataObj = data;
22870
+ writeString(bb, String(dataObj.owner || ''));
22871
+ serializeAsset(bb, String(dataObj.interest || '0.000 STEEM'));
22872
+ }
22873
+ /**
22874
+ * Serialize fill_vesting_withdraw operation.
22875
+ * Fields: from_account, to_account, withdrawn, deposited.
22876
+ */
22877
+ function serializeFillVestingWithdraw(bb, data) {
22878
+ const dataObj = data;
22879
+ writeString(bb, String(dataObj.from_account || ''));
22880
+ writeString(bb, String(dataObj.to_account || ''));
22881
+ serializeAsset(bb, String(dataObj.withdrawn || '0.000000 VESTS'));
22882
+ serializeAsset(bb, String(dataObj.deposited || '0.000 STEEM'));
22883
+ }
22884
+ /**
22885
+ * Serialize fill_convert_request operation.
22886
+ * Fields: owner, requestid, amount_in, amount_out.
22887
+ */
22888
+ function serializeFillConvertRequest(bb, data) {
22889
+ const dataObj = data;
22890
+ writeString(bb, String(dataObj.owner || ''));
22891
+ bb.writeUint32(dataObj.requestid ?? 0);
22892
+ serializeAsset(bb, String(dataObj.amount_in || '0.000 STEEM'));
22893
+ serializeAsset(bb, String(dataObj.amount_out || '0.000 STEEM'));
22894
+ }
22895
+ /**
22896
+ * Serialize fill_transfer_from_savings operation.
22897
+ * Fields: from, to, amount, request_id, memo.
22898
+ */
22899
+ function serializeFillTransferFromSavings(bb, data) {
22900
+ const dataObj = data;
22901
+ writeString(bb, String(dataObj.from || ''));
22902
+ writeString(bb, String(dataObj.to || ''));
22903
+ serializeAsset(bb, String(dataObj.amount || '0.000 STEEM'));
22904
+ bb.writeUint32(dataObj.request_id ?? 0);
22905
+ writeString(bb, String(dataObj.memo || ''));
22906
+ }
22907
+ /**
22908
+ * Serialize ChainProperties (used in pow, witness_update).
22909
+ * Fields: account_creation_fee (asset string), maximum_block_size (uint32), sbd_interest_rate (uint16).
22910
+ */
22911
+ function serializeChainProperties(bb, props) {
22912
+ const p = props || {};
22913
+ const fee = p.account_creation_fee;
22914
+ if (typeof fee === 'string' && fee.split(' ').length >= 2) {
22915
+ serializeAsset(bb, fee);
22916
+ }
22917
+ else {
22918
+ serializeAsset(bb, '0.000 STEEM');
22919
+ }
22920
+ bb.writeUint32(p.maximum_block_size ?? 0);
22921
+ bb.writeUint16(p.sbd_interest_rate ?? 0);
22922
+ }
22923
+ /**
22924
+ * Serialize POW inner struct (worker, input, signature, work).
22925
+ */
22926
+ function serializePOWInner(bb, work) {
22927
+ const w = work || {};
22928
+ writeString(bb, String(w.worker || ''));
22929
+ writeString(bb, String(w.input || ''));
22930
+ writeString(bb, String(w.signature || ''));
22931
+ writeString(bb, String(w.work || ''));
22932
+ }
22933
+ /**
22934
+ * Serialize pow operation.
22935
+ * Fields: worker_account, block_id, nonce (optional), work (POW), props (ChainProperties).
22936
+ */
22937
+ function serializePow(bb, data) {
22938
+ const dataObj = data;
22939
+ writeString(bb, String(dataObj.worker_account || ''));
22940
+ writeString(bb, String(dataObj.block_id || ''));
22941
+ const nonce = dataObj.nonce;
22942
+ if (nonce !== undefined && nonce !== null) {
22943
+ bb.writeUint8(1);
22944
+ bb.writeUint64(Number(nonce));
22945
+ }
22946
+ else {
22947
+ bb.writeUint8(0);
22948
+ }
22949
+ serializePOWInner(bb, dataObj.work);
22950
+ serializeChainProperties(bb, dataObj.props);
22951
+ }
22952
+ /**
22953
+ * Serialize pow2 operation.
22954
+ * Fields: input, pow_summary (opaque bytes; if string treated as hex).
22955
+ */
22956
+ function serializePow2(bb, data) {
22957
+ const dataObj = data;
22958
+ writeString(bb, String(dataObj.input || ''));
22959
+ const summary = dataObj.pow_summary;
22960
+ let bytes;
22961
+ if (typeof summary === 'string') {
22962
+ const hex = summary.startsWith('0x') ? summary.slice(2) : summary;
22963
+ bytes = Buffer.from(hex, 'hex');
22964
+ }
22965
+ else if (Buffer.isBuffer(summary)) {
22966
+ bytes = summary;
22967
+ }
22968
+ else {
22969
+ bytes = Buffer.alloc(0);
22970
+ }
22971
+ bb.writeVarint32(bytes.length);
22972
+ bb.append(bytes);
22973
+ }
22974
+ /**
22975
+ * Serialize witness_update operation.
22976
+ * Fields: owner, url, block_signing_key, props (ChainProperties), fee.
22977
+ */
22978
+ function serializeWitnessUpdate(bb, data) {
22979
+ const dataObj = data;
22980
+ writeString(bb, String(dataObj.owner || ''));
22981
+ writeString(bb, String(dataObj.url || ''));
22982
+ const key = dataObj.block_signing_key;
22983
+ if (typeof key === 'string') {
22984
+ const pubKey = PublicKey.fromStringOrThrow(key);
22985
+ bb.append(pubKey.toBuffer());
22986
+ }
22987
+ else if (Buffer.isBuffer(key)) {
22988
+ bb.append(key);
22989
+ }
22990
+ else if (key && typeof key.toBuffer === 'function') {
22991
+ bb.append(key.toBuffer());
22992
+ }
22993
+ else {
22994
+ bb.append(Buffer.alloc(33));
22995
+ }
22996
+ serializeChainProperties(bb, dataObj.props);
22997
+ serializeAsset(bb, String(dataObj.fee || '0.000 STEEM'));
22998
+ }
22999
+ /**
23000
+ * Serialize witness_set_properties operation.
23001
+ * Fields: owner, props (map string -> bytes), extensions.
23002
+ */
23003
+ function serializeWitnessSetProperties(bb, data) {
23004
+ const dataObj = data;
23005
+ writeString(bb, String(dataObj.owner || ''));
23006
+ const props = dataObj.props;
23007
+ const keys = props ? Object.keys(props).sort() : [];
23008
+ bb.writeVarint32(keys.length);
23009
+ for (const k of keys) {
23010
+ writeString(bb, k);
23011
+ const v = props[k];
23012
+ const buf = typeof v === 'string' ? Buffer.from(v, 'utf8') : Buffer.isBuffer(v) ? v : Buffer.alloc(0);
23013
+ bb.writeVarint32(buf.length);
23014
+ bb.append(buf);
23015
+ }
23016
+ serializeExtensions(bb, dataObj.extensions);
23017
+ }
23018
+ /**
23019
+ * Serialize account_witness_vote operation.
23020
+ * Fields: account, witness, approve.
23021
+ */
23022
+ function serializeAccountWitnessVote(bb, data) {
23023
+ const dataObj = data;
23024
+ writeString(bb, String(dataObj.account || ''));
23025
+ writeString(bb, String(dataObj.witness || ''));
23026
+ serializeBool(bb, dataObj.approve);
23027
+ }
23028
+ /**
23029
+ * Serialize account_witness_proxy operation.
23030
+ * Fields: account, proxy.
23031
+ */
23032
+ function serializeAccountWitnessProxy(bb, data) {
23033
+ const dataObj = data;
23034
+ writeString(bb, String(dataObj.account || ''));
23035
+ writeString(bb, String(dataObj.proxy || ''));
23036
+ }
23037
+ /**
23038
+ * Serialize custom operation (required_auths, id, data).
23039
+ * id is uint16 in protocol; data is bytes.
23040
+ */
23041
+ function serializeCustom(bb, data) {
23042
+ const dataObj = data;
23043
+ const requiredAuths = Array.isArray(dataObj.required_auths)
23044
+ ? dataObj.required_auths.slice().sort()
23045
+ : [];
23046
+ bb.writeVarint32(requiredAuths.length);
23047
+ for (const account of requiredAuths) {
23048
+ writeString(bb, String(account));
23049
+ }
23050
+ bb.writeUint16(dataObj.id ?? 0);
23051
+ const dataBytes = dataObj.data;
23052
+ let buf;
23053
+ if (typeof dataBytes === 'string') {
23054
+ const hex = dataBytes.startsWith('0x') ? dataBytes.slice(2) : dataBytes;
23055
+ buf = Buffer.from(hex, 'hex');
23056
+ }
23057
+ else if (Buffer.isBuffer(dataBytes)) {
23058
+ buf = dataBytes;
23059
+ }
23060
+ else {
23061
+ buf = Buffer.alloc(0);
23062
+ }
23063
+ bb.writeVarint32(buf.length);
23064
+ bb.append(buf);
23065
+ }
23066
+ /**
23067
+ * Serialize custom_binary operation.
23068
+ * Fields: id (string), data (bytes).
23069
+ */
23070
+ function serializeCustomBinary(bb, data) {
23071
+ const dataObj = data;
23072
+ writeString(bb, String(dataObj.id || ''));
23073
+ const dataBytes = dataObj.data;
23074
+ let buf;
23075
+ if (typeof dataBytes === 'string') {
23076
+ const hex = dataBytes.startsWith('0x') ? dataBytes.slice(2) : dataBytes;
23077
+ buf = Buffer.from(hex, 'hex');
23078
+ }
23079
+ else if (Buffer.isBuffer(dataBytes)) {
23080
+ buf = dataBytes;
23081
+ }
23082
+ else {
23083
+ buf = Buffer.alloc(0);
23084
+ }
23085
+ bb.writeVarint32(buf.length);
23086
+ bb.append(buf);
23087
+ }
23088
+ /**
23089
+ * Serialize comment_options operation.
23090
+ * Fields: author, permlink, max_accepted_payout, percent_steem_dollars, allow_votes, allow_curation_rewards, extensions.
23091
+ */
23092
+ function serializeCommentOptions(bb, data) {
23093
+ const dataObj = data;
23094
+ writeString(bb, String(dataObj.author || ''));
23095
+ writeString(bb, String(dataObj.permlink || ''));
23096
+ serializeAsset(bb, String(dataObj.max_accepted_payout || '1000000.000 SBD'));
23097
+ bb.writeUint16(dataObj.percent_steem_dollars ?? 0);
23098
+ serializeBool(bb, dataObj.allow_votes);
23099
+ serializeBool(bb, dataObj.allow_curation_rewards);
23100
+ serializeExtensions(bb, dataObj.extensions);
23101
+ }
23102
+ /**
23103
+ * Serialize custom_json operation
23104
+ */
23105
+ function serializeCustomJson(bb, data) {
23106
+ const dataObj = data;
23107
+ // Serialize required_auths (flat_set<account_name_type>)
23108
+ // Set serialization: varint32 length, then each element
23109
+ const requiredAuths = Array.isArray(dataObj.required_auths)
23110
+ ? dataObj.required_auths.slice().sort()
23111
+ : [];
23112
+ bb.writeVarint32(requiredAuths.length);
23113
+ for (const account of requiredAuths) {
23114
+ writeString(bb, String(account));
23115
+ }
23116
+ // Serialize required_posting_auths (flat_set<account_name_type>)
23117
+ const requiredPostingAuths = Array.isArray(dataObj.required_posting_auths)
23118
+ ? dataObj.required_posting_auths.slice().sort()
23119
+ : [];
23120
+ bb.writeVarint32(requiredPostingAuths.length);
23121
+ for (const account of requiredPostingAuths) {
23122
+ writeString(bb, String(account));
23123
+ }
23124
+ // Serialize id (string)
23125
+ writeString(bb, String(dataObj.id || ''));
23126
+ // Serialize json (string)
23127
+ writeString(bb, String(dataObj.json || '{}'));
23128
+ }
23129
+ /**
23130
+ * Serialize Authority
23131
+ */
23132
+ function serializeAuthority(bb, auth) {
23133
+ const authObj = auth;
23134
+ bb.writeUint32(authObj.weight_threshold || 1);
23135
+ // Account auths (map<string, uint16>)
23136
+ const accountAuths = (Array.isArray(authObj.account_auths) ? authObj.account_auths : []);
23137
+ // Maps in Steem serialization are sorted by key
23138
+ const accountAuthsArray = accountAuths;
23139
+ accountAuthsArray.sort((a, b) => {
23140
+ const aKey = Array.isArray(a) && a[0] ? String(a[0]) : '';
23141
+ const bKey = Array.isArray(b) && b[0] ? String(b[0]) : '';
23142
+ return aKey.localeCompare(bKey);
23143
+ });
23144
+ bb.writeVarint32(accountAuths.length);
23145
+ for (const authEntry of accountAuths) {
23146
+ if (Array.isArray(authEntry) && authEntry.length >= 2) {
23147
+ writeString(bb, String(authEntry[0]));
23148
+ bb.writeUint16(authEntry[1]);
23149
+ }
23150
+ }
23151
+ // Key auths (map<public_key, uint16>)
23152
+ const keyAuths = (Array.isArray(authObj.key_auths) ? authObj.key_auths : []);
23153
+ // Maps in Steem serialization are sorted by key (public key string)
23154
+ // But serialized as bytes. Usually sorting by string representation of public key works.
23155
+ const keyAuthsArray = keyAuths;
23156
+ keyAuthsArray.sort((a, b) => {
23157
+ const aKey = Array.isArray(a) && a[0] ? String(a[0]) : '';
23158
+ const bKey = Array.isArray(b) && b[0] ? String(b[0]) : '';
23159
+ return aKey.localeCompare(bKey);
23160
+ });
23161
+ bb.writeVarint32(keyAuths.length);
23162
+ for (const keyAuth of keyAuths) {
23163
+ if (Array.isArray(keyAuth) && keyAuth.length >= 2) {
23164
+ const keyStr = String(keyAuth[0]);
23165
+ const weight = keyAuth[1];
23166
+ const pubKey = PublicKey.fromStringOrThrow(keyStr);
23167
+ bb.append(pubKey.toBuffer());
23168
+ bb.writeUint16(weight);
23169
+ }
23170
+ }
23171
+ }
23172
+ /**
23173
+ * Serialize asset (STEEM/SBD/VESTS style string) to binary.
23174
+ *
23175
+ * Format: int64 amount (little-endian) + uint8 precision + 7-byte symbol (UTF-8, null-padded).
23176
+ *
23177
+ * This helper is reused across all operations中涉及资产字段的地方,例如:
23178
+ * - amount / vesting_shares / reward_* / *_pays
23179
+ */
23180
+ function serializeAsset(bb, amount) {
23181
+ const parts = amount.split(' ');
23182
+ const valueStr = parts[0] || '0.000';
23183
+ const symbol = parts[1] || 'STEEM';
23184
+ const [intPart, decPart = ''] = valueStr.split('.');
23185
+ const precision = decPart.length;
23186
+ const amountValue = parseInt(intPart + decPart.padEnd(precision, '0'), 10) || 0;
23187
+ bb.writeInt64(amountValue);
23188
+ bb.writeUint8(precision);
23189
+ const symbolBytes = Buffer.from(symbol, 'utf8');
23190
+ bb.append(symbolBytes);
23191
+ for (let i = symbolBytes.length; i < 7; i++) {
23192
+ bb.writeUint8(0);
23193
+ }
23194
+ }
23195
+ /**
23196
+ * Write a string using ByteBuffer's writeVString method.
23197
+ * 所有字符串字段统一通过该 helper 序列化,避免直接到处调用 ByteBuffer API。
23198
+ */
23199
+ function writeString(bb, str) {
23200
+ bb.writeVString(str);
23201
+ }
23202
+ /**
23203
+ * Serialize a time_point_sec-style field.
23204
+ *
23205
+ * 接受 ISO 字符串 / Date / 秒级数字,最终写入 uint32(自 epoch 起的秒数)。
23206
+ * 常用于 proposal start/end、escrow_deadline 等字段。
23207
+ */
23208
+ function serializeTimePointSec(bb, value) {
23209
+ let seconds;
23210
+ if (typeof value === 'string') {
23211
+ const iso = value.endsWith('Z') ? value : `${value}Z`;
23212
+ const d = new Date(iso);
23213
+ seconds = Math.floor(d.getTime() / 1000);
23214
+ }
23215
+ else if (value instanceof Date) {
23216
+ seconds = Math.floor(value.getTime() / 1000);
23217
+ }
23218
+ else if (typeof value === 'number') {
23219
+ // 这里假定已是秒级时间戳
23220
+ seconds = value;
23221
+ }
23222
+ else {
23223
+ seconds = 0;
23224
+ }
23225
+ bb.writeUint32(seconds);
23226
+ }
23227
+ /**
23228
+ * Serialize a generic bool flag as uint8(0/1).
23229
+ * 后续在多处 optional / approve / decline 字段可统一复用。
23230
+ */
23231
+ function serializeBool(bb, value) {
23232
+ bb.writeUint8(value ? 1 : 0);
23233
+ }
23234
+ /**
23235
+ * Serialize a future_extensions / extensions 风格字段。
23236
+ *
23237
+ * 目前大多数链上交易中 extensions 仍为空集合,协议格式是:
23238
+ * - varint32 length
23239
+ * - 后续按约定序列化各元素(当前实现仅支持空或简单 JSON 字符串)
23240
+ *
23241
+ * 为兼容现有使用场景,这里暂时只写入长度,忽略实际内容;当需要支持
23242
+ * 具体 extension 类型时,可以在保持签名兼容性的前提下扩展实现。
23243
+ */
23244
+ function serializeExtensions(bb, extensions) {
23245
+ if (!Array.isArray(extensions) || extensions.length === 0) {
23246
+ bb.writeVarint32(0);
23247
+ return;
23248
+ }
23249
+ // 协议上 extensions 是 future_extensions,目前主网基本为 0。
23250
+ // 为避免序列化出与 C++ 节点不兼容的数据,这里保守起见仍写入 0。
23251
+ // 如果未来需要支持非空 extensions,可在测试验证后放开以下逻辑:
23252
+ //
23253
+ // bb.writeVarint32(extensions.length);
23254
+ // for (const ext of extensions) {
23255
+ // const json = JSON.stringify(ext ?? null);
23256
+ // writeString(bb, json);
23257
+ // }
23258
+ bb.writeVarint32(0);
23259
+ }
23260
+
23261
+ class Serializer {
23262
+ static fromBuffer(buffer) {
23263
+ const bb = ByteBuffer.fromBinary(buffer.toString('binary'), ByteBuffer.LITTLE_ENDIAN);
23264
+ // Require at least 66 bytes for two 33-byte public keys before reading
23265
+ if (bb.remaining() < 66) {
23266
+ throw new Error('Invalid memo: insufficient data for public keys');
23267
+ }
23268
+ // Read public keys
23269
+ const fromKey = PublicKey.fromBuffer(bb.readBytes(33).toBuffer());
23270
+ const toKey = PublicKey.fromBuffer(bb.readBytes(33).toBuffer());
23271
+ // Read nonce (uint64)
23272
+ const nonce = bb.readUint64().toString();
23273
+ // Read checksum (uint32)
23274
+ const check = bb.readUint32();
23275
+ // Read encrypted data
23276
+ const encryptedLength = bb.readVarint32();
23277
+ const encrypted = bb.readBytes(encryptedLength).toString('hex');
23278
+ return {
23279
+ from: fromKey,
23280
+ to: toKey,
23281
+ nonce,
23282
+ check,
23283
+ encrypted
23284
+ };
23285
+ }
23286
+ static toBuffer(memo) {
23287
+ const bb = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
23288
+ // Write public keys
23289
+ bb.append(memo.from.toBuffer());
23290
+ bb.append(memo.to.toBuffer());
23291
+ // Write nonce (uint64) - must be string representing unsigned 64-bit integer
23292
+ let nonceLong;
23293
+ if (typeof memo.nonce === 'string') {
23294
+ try {
22380
23295
  nonceLong = Long.fromString(memo.nonce, true, 10); // unsigned, base 10
22381
23296
  }
22382
23297
  catch {
22383
- // Fallback: try as number if string parsing fails
22384
- const num = Number(memo.nonce);
22385
- if (!isNaN(num) && isFinite(num)) {
22386
- nonceLong = Long.fromNumber(num, true); // unsigned
22387
- }
22388
- else {
22389
- throw new Error(`Invalid nonce format: ${memo.nonce}`);
22390
- }
23298
+ throw new Error(`Invalid nonce format: ${memo.nonce}. Must be a string representing an unsigned 64-bit integer.`);
22391
23299
  }
22392
23300
  }
22393
23301
  else {
@@ -22409,7 +23317,7 @@ class Serializer {
22409
23317
  const transaction = {
22410
23318
  toBuffer(trx) {
22411
23319
  // Use binary serialization for proper signature generation
22412
- return serializeTransaction$1(trx);
23320
+ return serializeTransaction(trx);
22413
23321
  }
22414
23322
  };
22415
23323
  const signed_transaction = {
@@ -22421,7 +23329,7 @@ const signed_transaction = {
22421
23329
  }
22422
23330
  };
22423
23331
 
22424
- const serializer$1 = /*#__PURE__*/Object.freeze({
23332
+ const serializer = /*#__PURE__*/Object.freeze({
22425
23333
  __proto__: null,
22426
23334
  Serializer: Serializer,
22427
23335
  signed_transaction: signed_transaction,
@@ -22472,12 +23380,16 @@ const Auth = {
22472
23380
  let isWif = false;
22473
23381
  try {
22474
23382
  const bufWif = Buffer.from(bs58.decode(privWif));
23383
+ // Valid WIF: 1 byte version + 32 bytes key + 4 bytes checksum = 37 bytes
23384
+ if (bufWif.length !== 37) {
23385
+ return false;
23386
+ }
22475
23387
  const privKey = bufWif.slice(0, -4);
22476
23388
  const checksum = bufWif.slice(-4);
22477
23389
  let newChecksum = sha256$1(privKey);
22478
23390
  newChecksum = sha256$1(newChecksum);
22479
23391
  newChecksum = newChecksum.slice(0, 4);
22480
- if (checksum.toString() === newChecksum.toString()) {
23392
+ if (constantTimeCompare(checksum, Buffer.from(newChecksum))) {
22481
23393
  isWif = true;
22482
23394
  }
22483
23395
  }
@@ -23646,20 +24558,29 @@ class Broadcast {
23646
24558
  try {
23647
24559
  // Prepare the transaction (fetch global props, block header, etc.)
23648
24560
  const transaction = await broadcastMethods._prepareTransaction.call(this, tx);
23649
- // Debug: Print transaction, digest, and hex before signing (if debug enabled)
24561
+ // Debug: Print transaction info (full details only in development to avoid leaking sensitive data)
23650
24562
  const { debug } = await Promise.resolve().then(function () { return debug$1; });
23651
24563
  if (debug.isEnabled('transaction')) {
23652
- const { transaction: transactionSerializer } = await Promise.resolve().then(function () { return serializer$1; });
23653
- const { getConfig } = await Promise.resolve().then(function () { return config$1; });
23654
- // sha256 is already imported at the top
23655
- const buf = transactionSerializer.toBuffer(transaction);
23656
- const chainId = Buffer.from(getConfig().get('chain_id') || '', 'hex');
23657
- const digest = Buffer.from(sha256$2(Buffer.concat([chainId, buf])));
23658
- debug.transaction('\n=== Transaction Debug Info (before signing) ===');
23659
- debug.transaction('Transaction:', JSON.stringify(transaction, null, 2));
23660
- debug.transaction('Transaction.toHex():', buf.toString('hex'));
23661
- debug.transaction('Digest (sha256(chain_id + transaction)):', digest.toString('hex'));
23662
- debug.transaction('===============================================\n');
24564
+ const isDev = process.env.NODE_ENV === 'development';
24565
+ if (isDev) {
24566
+ const { transaction: transactionSerializer } = await Promise.resolve().then(function () { return serializer; });
24567
+ const { getConfig } = await Promise.resolve().then(function () { return config$1; });
24568
+ const buf = transactionSerializer.toBuffer(transaction);
24569
+ const chainId = Buffer.from(getConfig().get('chain_id') || '', 'hex');
24570
+ const digest = Buffer.from(sha256$2(Buffer.concat([chainId, buf])));
24571
+ debug.transaction('\n=== Transaction Debug Info (before signing) ===');
24572
+ debug.transaction('Transaction:', JSON.stringify(transaction, null, 2));
24573
+ debug.transaction('Transaction.toHex():', buf.toString('hex'));
24574
+ debug.transaction('Digest (sha256(chain_id + transaction)):', digest.toString('hex'));
24575
+ debug.transaction('===============================================\n');
24576
+ }
24577
+ else {
24578
+ const tx = transaction;
24579
+ debug.transaction('Transaction signed:', {
24580
+ operations: tx.operations?.length ?? 0,
24581
+ ref_block_num: tx.ref_block_num
24582
+ });
24583
+ }
23663
24584
  }
23664
24585
  // Ensure privKeys is always an array for signTransaction
23665
24586
  const keysArray = Array.isArray(privKeys)
@@ -25048,19 +25969,15 @@ const cbc = /* @__PURE__ */ wrapCipher({ blockSize: 16, nonceLength: 16 }, funct
25048
25969
  };
25049
25970
  });
25050
25971
 
25051
- let uniqueNonceEntropy = null;
25052
25972
  function sha512Buffer(data) {
25053
25973
  const result = sha512(data);
25054
25974
  return Buffer.isBuffer(result) ? result : Buffer.from(result, 'hex');
25055
25975
  }
25056
25976
  class Aes {
25057
25977
  static uniqueNonce() {
25058
- if (uniqueNonceEntropy === null) {
25059
- uniqueNonceEntropy = Math.floor(Math.random() * 0xFFFF);
25060
- }
25061
- let long = Long.fromNumber(Date.now());
25062
- const entropy = ++uniqueNonceEntropy % 0xFFFF;
25063
- long = long.shiftLeft(16).or(Long.fromNumber(entropy));
25978
+ const now = Date.now() >>> 0; // low 32 bits of ms
25979
+ const randomPart = randomBytes(4).readUInt32BE(0);
25980
+ const long = Long.fromNumber(now, true).shiftLeft(32).or(Long.fromNumber(randomPart, true));
25064
25981
  return long.toString();
25065
25982
  }
25066
25983
  static encrypt(private_key, public_key, message, nonce = Aes.uniqueNonce()) {
@@ -25214,7 +26131,14 @@ function encode(private_key, public_key, memo, testNonce) {
25214
26131
  const serialized = Serializer.toBuffer(memoData);
25215
26132
  return '#' + bs58.encode(serialized);
25216
26133
  }
25217
- function decode(private_key, memo) {
26134
+ /**
26135
+ * Decode an encrypted memo.
26136
+ * @param private_key - Our private key (WIF or PrivateKey)
26137
+ * @param memo - Encrypted memo string (leading #)
26138
+ * @param expectedRecipientPubKey - If we are the sender, optionally verify the memo's 'to' matches this (prevents wrong-recipient decryption)
26139
+ * @returns Decrypted memo with leading #, or original string on failure
26140
+ */
26141
+ function decode(private_key, memo, expectedRecipientPubKey) {
25218
26142
  if (!memo || typeof memo !== 'string') {
25219
26143
  return memo;
25220
26144
  }
@@ -25234,7 +26158,24 @@ function decode(private_key, memo) {
25234
26158
  const memoData = Serializer.fromBuffer(Buffer.from(decoded));
25235
26159
  const { from, to, nonce, check, encrypted } = memoData;
25236
26160
  const pubkey = privateKey.toPublicKey().toString();
25237
- const otherpub = pubkey === from.toString() ? to : from;
26161
+ let otherpub;
26162
+ if (pubkey === from.toString()) {
26163
+ otherpub = to;
26164
+ if (expectedRecipientPubKey !== undefined) {
26165
+ const expected = typeof expectedRecipientPubKey === 'string'
26166
+ ? PublicKey.fromString(expectedRecipientPubKey)
26167
+ : expectedRecipientPubKey;
26168
+ if (!expected || otherpub.toString() !== expected.toString()) {
26169
+ throw new Error('Memo encrypted for unexpected recipient');
26170
+ }
26171
+ }
26172
+ }
26173
+ else if (pubkey === to.toString()) {
26174
+ otherpub = from;
26175
+ }
26176
+ else {
26177
+ throw new Error('Memo not encrypted for this key');
26178
+ }
25238
26179
  const decrypted = Aes.decrypt(privateKey, otherpub, nonce, encrypted, check);
25239
26180
  const mbuf = ByteBuffer.fromBinary(decrypted.toString('binary'), ByteBuffer.LITTLE_ENDIAN);
25240
26181
  try {
@@ -25308,439 +26249,6 @@ const operations = /*#__PURE__*/Object.freeze({
25308
26249
  createVote: createVote
25309
26250
  });
25310
26251
 
25311
- /**
25312
- * Convert implementation to support serializing types.
25313
- */
25314
- class Convert {
25315
- constructor(type) {
25316
- this.type = type;
25317
- }
25318
- toHex(value) {
25319
- if (!this.type || typeof this.type.toHex !== 'function') {
25320
- throw new Error(`Type ${this.type} does not implement toHex method`);
25321
- }
25322
- return this.type.toHex(value);
25323
- }
25324
- fromHex(hex) {
25325
- if (!this.type || typeof this.type.fromHex !== 'function') {
25326
- throw new Error(`Type ${this.type} does not implement fromHex method`);
25327
- }
25328
- return this.type.fromHex(hex);
25329
- }
25330
- fromObject(obj) {
25331
- if (!this.type || typeof this.type.fromObject !== 'function') {
25332
- throw new Error(`Type ${this.type} does not implement fromObject method`);
25333
- }
25334
- return this.type.fromObject(obj);
25335
- }
25336
- toObject(obj) {
25337
- if (!this.type || typeof this.type.toObject !== 'function') {
25338
- throw new Error(`Type ${this.type} does not implement toObject method`);
25339
- }
25340
- return this.type.toObject(obj);
25341
- }
25342
- }
25343
- // Export a factory function to create Convert instances
25344
- function convert (type) {
25345
- return new Convert(type);
25346
- }
25347
-
25348
- // Minimal implementation for types to satisfy test imports
25349
- const vote_id = {
25350
- fromObject: (id) => {
25351
- if (typeof id !== 'string') {
25352
- throw new Error('Expected string representing vote_id');
25353
- }
25354
- // Handle out of range test cases
25355
- if (id === '256:0' || id === '0:16777216') {
25356
- throw new Error('out of range');
25357
- }
25358
- const parts = id.split(':');
25359
- if (parts.length !== 2) {
25360
- throw new Error('vote_id should be in the form of type:id');
25361
- }
25362
- const typeNum = parseInt(parts[0], 10);
25363
- const idNum = parseInt(parts[1], 10);
25364
- if (isNaN(typeNum) || isNaN(idNum)) {
25365
- throw new Error('Invalid vote_id format');
25366
- }
25367
- // Check range for proper implementation
25368
- if (typeNum < 0 || typeNum > 255 || idNum < 0 || idNum > 16777215) {
25369
- throw new Error('out of range');
25370
- }
25371
- return id; // Return the original string for further processing
25372
- },
25373
- toHex: (id) => {
25374
- // Explicit test cases
25375
- if (id === '255:0')
25376
- return 'ff000000';
25377
- if (id === '0:16777215')
25378
- return '00ffffff';
25379
- // If id is already in the right format, use it directly for tests
25380
- if (/^[0-9a-f]{8}$/.test(id)) {
25381
- return id;
25382
- }
25383
- // Otherwise, parse the colon format
25384
- try {
25385
- const parts = id.split(':');
25386
- if (parts.length !== 2) {
25387
- throw new Error('vote_id should be in the form of type:id');
25388
- }
25389
- const typeNum = parseInt(parts[0], 10);
25390
- const idNum = parseInt(parts[1], 10);
25391
- if (isNaN(typeNum) || isNaN(idNum)) {
25392
- throw new Error('Invalid vote_id format');
25393
- }
25394
- // Check range
25395
- if (typeNum < 0 || typeNum > 255 || idNum < 0 || idNum > 16777215) {
25396
- throw new Error('out of range');
25397
- }
25398
- // Format as 8-character hex string
25399
- return typeNum.toString(16).padStart(2, '0') + idNum.toString(16).padStart(6, '0');
25400
- }
25401
- catch (e) {
25402
- // For test cases, rethrow specific errors
25403
- if (e instanceof Error && e.message.includes('out of range')) {
25404
- throw e;
25405
- }
25406
- // For other errors in test cases, don't break tests
25407
- console.error('Error in vote_id.toHex:', e);
25408
- return ''; // Return empty string which will fail the test explicitly
25409
- }
25410
- }
25411
- };
25412
- const set = (_type) => ({
25413
- fromObject: (arr) => {
25414
- if (!Array.isArray(arr)) {
25415
- throw new Error('Expected array for set type');
25416
- }
25417
- // Only check for duplicates for 'string' and 'number' types using a JS object as a map
25418
- const dup_map = {};
25419
- for (let i = 0; i < arr.length; i++) {
25420
- const o = arr[i];
25421
- const ref = typeof o;
25422
- if (ref === 'string' || ref === 'number') {
25423
- const key = o;
25424
- if (dup_map[key] !== undefined) {
25425
- throw new Error('duplicate (set)');
25426
- }
25427
- dup_map[key] = true;
25428
- }
25429
- }
25430
- // Sort using the original logic
25431
- return [...arr].sort((a, b) => {
25432
- if (typeof a === 'number' && typeof b === 'number')
25433
- return a - b;
25434
- if (Buffer.isBuffer(a) && Buffer.isBuffer(b))
25435
- return a.toString('hex').localeCompare(b.toString('hex'));
25436
- if (typeof a === 'string' && typeof b === 'string')
25437
- return a.localeCompare(b);
25438
- const aStr = a != null ? String(a) : '';
25439
- const bStr = b != null ? String(b) : '';
25440
- return aStr.localeCompare(bStr);
25441
- });
25442
- },
25443
- toObject: (set) => [...set].sort((a, b) => {
25444
- if (typeof a === 'number' && typeof b === 'number')
25445
- return a - b;
25446
- if (Buffer.isBuffer(a) && Buffer.isBuffer(b))
25447
- return a.toString('hex').localeCompare(b.toString('hex'));
25448
- if (typeof a === 'string' && typeof b === 'string')
25449
- return a.localeCompare(b);
25450
- const aStr = a != null ? String(a) : '';
25451
- const bStr = b != null ? String(b) : '';
25452
- return aStr.localeCompare(bStr);
25453
- }),
25454
- toHex: (arr) => {
25455
- // Explicit test case handling
25456
- if (JSON.stringify(arr) === JSON.stringify([1, 0])) {
25457
- return '020001';
25458
- }
25459
- // Fallback implementation
25460
- const buffer = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
25461
- buffer.writeUint8(arr.length);
25462
- for (const item of arr) {
25463
- buffer.writeUint8(item ? 1 : 0); // For bool types
25464
- }
25465
- buffer.flip();
25466
- return buffer.toHex();
25467
- }
25468
- });
25469
- const map = (_keyType, _valueType) => ({
25470
- fromObject: (arr) => {
25471
- if (!Array.isArray(arr)) {
25472
- throw new Error('Expected array for map type');
25473
- }
25474
- // Only check for duplicate primitive keys ('string' and 'number') using a JS object as a map
25475
- const dup_map = {};
25476
- for (let i = 0; i < arr.length; i++) {
25477
- const o = arr[i][0];
25478
- const ref = typeof o;
25479
- if (ref === 'string' || ref === 'number') {
25480
- const key = o;
25481
- if (dup_map[key] !== undefined) {
25482
- throw new Error('duplicate (map)');
25483
- }
25484
- dup_map[key] = true;
25485
- }
25486
- }
25487
- // Sort by key using the original logic
25488
- return [...arr].sort((a, b) => {
25489
- const ka = a[0];
25490
- const kb = b[0];
25491
- if (typeof ka === 'number' && typeof kb === 'number')
25492
- return ka - kb;
25493
- if (Buffer.isBuffer(ka) && Buffer.isBuffer(kb))
25494
- return ka.toString('hex').localeCompare(kb.toString('hex'));
25495
- if (typeof ka === 'string' && typeof kb === 'string')
25496
- return ka.localeCompare(kb);
25497
- return String(ka).localeCompare(String(kb));
25498
- });
25499
- },
25500
- toObject: (map) => [...map].sort((a, b) => {
25501
- const ka = a[0];
25502
- const kb = b[0];
25503
- if (typeof ka === 'number' && typeof kb === 'number')
25504
- return ka - kb;
25505
- if (Buffer.isBuffer(ka) && Buffer.isBuffer(kb))
25506
- return ka.toString('hex').localeCompare(kb.toString('hex'));
25507
- if (typeof ka === 'string' && typeof kb === 'string')
25508
- return ka.localeCompare(kb);
25509
- return String(ka).localeCompare(String(kb));
25510
- }),
25511
- toHex: (arr) => {
25512
- // Explicit test case
25513
- if (JSON.stringify(arr) === JSON.stringify([[1, 1], [0, 0]])) {
25514
- return '0200000101';
25515
- }
25516
- // Fallback implementation
25517
- const buffer = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
25518
- buffer.writeUint8(arr.length);
25519
- for (const [key, value] of arr) {
25520
- buffer.writeUint8(key ? 1 : 0); // For bool keys
25521
- buffer.writeUint8(value ? 1 : 0); // For bool values
25522
- }
25523
- buffer.flip();
25524
- return buffer.toHex();
25525
- }
25526
- });
25527
- const bool = {
25528
- toHex: (value) => {
25529
- return value ? '01' : '00';
25530
- }
25531
- };
25532
- const string = {
25533
- toHex: (value) => {
25534
- return Buffer.from(value, 'utf8').toString('hex');
25535
- }
25536
- };
25537
- const public_key = {
25538
- toHex: (key) => {
25539
- return Buffer.from(key, 'utf8').toString('hex');
25540
- }
25541
- };
25542
- const uint16 = {
25543
- toHex: (value) => {
25544
- const buffer = new ByteBuffer(2, ByteBuffer.LITTLE_ENDIAN);
25545
- buffer.writeUint16(value);
25546
- buffer.flip();
25547
- return buffer.toHex();
25548
- }
25549
- };
25550
- // For precision_number, which is challenging to implement fully
25551
- const _internal$1 = {
25552
- decimal_precision_string: (value, precision) => {
25553
- // Remove leading/trailing whitespace
25554
- let number_string = (value || '').trim();
25555
- // Handle empty or dash
25556
- if (!number_string || number_string === '-') {
25557
- return precision === 0 ? '0' : '0'.padEnd(precision + 1, '0');
25558
- }
25559
- // Handle sign
25560
- let sign = '';
25561
- if (number_string[0] === '-') {
25562
- sign = '-';
25563
- number_string = number_string.slice(1);
25564
- }
25565
- // Validate format
25566
- const match = number_string.match(/^([0-9]*)(?:\.([0-9]*))?$/);
25567
- if (!match) {
25568
- throw new Error('Invalid number');
25569
- }
25570
- let int_part = match[1] || '';
25571
- let dec_part = match[2] || '';
25572
- // Remove leading zeros from int_part
25573
- int_part = int_part.replace(/^0+/, '');
25574
- if (!int_part)
25575
- int_part = '0';
25576
- // Check for overflow
25577
- if (dec_part.length > precision) {
25578
- throw new Error('overflow');
25579
- }
25580
- // Pad dec_part with zeros
25581
- while (dec_part.length < precision) {
25582
- dec_part += '0';
25583
- }
25584
- // Truncate dec_part to precision
25585
- dec_part = dec_part.substring(0, precision);
25586
- // If sign is negative and all digits are zero, remove sign
25587
- if (sign && /^0+$/.test(int_part + dec_part)) {
25588
- sign = '';
25589
- }
25590
- // If all digits are zero, return '0' (or '-0' if negative)
25591
- if (/^0+$/.test(int_part + dec_part)) {
25592
- return sign + '0';
25593
- }
25594
- // Always concatenate int_part and dec_part (remove decimal point)
25595
- return sign + int_part + dec_part;
25596
- },
25597
- precision_number_long: (value, precision) => {
25598
- // Throw overflow for the specific test case and for precision > 15
25599
- if (value === '92233720368547758075' || precision > 15) {
25600
- throw new Error('overflow');
25601
- }
25602
- }
25603
- };
25604
- const type_id = {
25605
- toHex: (value) => {
25606
- return Buffer.from(value, 'utf8').toString('hex');
25607
- }
25608
- };
25609
- const protocol_id_type = (_name) => ({
25610
- toHex: (value) => {
25611
- const buffer = new ByteBuffer(8, ByteBuffer.LITTLE_ENDIAN);
25612
- buffer.writeUint64(value);
25613
- buffer.flip();
25614
- return buffer.toHex();
25615
- }
25616
- });
25617
-
25618
- const types = /*#__PURE__*/Object.freeze({
25619
- __proto__: null,
25620
- _internal: _internal$1,
25621
- bool: bool,
25622
- map: map,
25623
- protocol_id_type: protocol_id_type,
25624
- public_key: public_key,
25625
- set: set,
25626
- string: string,
25627
- type_id: type_id,
25628
- uint16: uint16,
25629
- vote_id: vote_id
25630
- });
25631
-
25632
- // Ported logic from original steem-js
25633
- // Helper: 64-bit signed integer range
25634
- const MAX_INT64 = BigInt('9223372036854775807');
25635
- const MIN_INT64 = BigInt('-9223372036854775808');
25636
- const _internal = {
25637
- decimal_precision_string: (number, precision) => {
25638
- if (number === undefined || number === null)
25639
- throw new Error('number required');
25640
- if (precision === undefined || precision === null)
25641
- throw new Error('precision required');
25642
- const number_string = String(number).trim();
25643
- precision = Number(precision);
25644
- // remove leading zeros (not suffixing)
25645
- const number_parts = number_string.match(/^-?0*([0-9]*)\.?([0-9]*)$/);
25646
- if (!number_parts) {
25647
- throw new Error(`Invalid number: ${number_string}`);
25648
- }
25649
- let sign = number_string.charAt(0) === '-' ? '-' : '';
25650
- let int_part = number_parts[1];
25651
- let decimal_part = number_parts[2] || '';
25652
- // remove trailing zeros
25653
- while (/0$/.test(decimal_part)) {
25654
- decimal_part = decimal_part.substring(0, decimal_part.length - 1);
25655
- }
25656
- const zero_pad_count = precision - decimal_part.length;
25657
- if (zero_pad_count < 0) {
25658
- throw new Error(`overflow, up to ${precision} decimals may be used`);
25659
- }
25660
- if (sign === '-' && !/[1-9]/.test(int_part + decimal_part)) {
25661
- sign = '';
25662
- }
25663
- if (int_part === '') {
25664
- int_part = '0';
25665
- }
25666
- for (let i = 0; i < zero_pad_count; i++) {
25667
- decimal_part += '0';
25668
- }
25669
- return sign + int_part + decimal_part;
25670
- }
25671
- };
25672
- const to_bigint64 = (number_or_string, precision) => {
25673
- // Convert to implied decimal string
25674
- const implied = _internal.decimal_precision_string(number_or_string, precision);
25675
- // Convert to BigInt
25676
- const value = BigInt(implied);
25677
- // Check 64-bit signed integer range
25678
- if (value > MAX_INT64 || value < MIN_INT64) {
25679
- throw new Error('overflow');
25680
- }
25681
- return value;
25682
- };
25683
- const to_string64 = (input, precision) => {
25684
- // Convert to string with implied decimal
25685
- return _internal.decimal_precision_string(String(input), precision);
25686
- };
25687
-
25688
- const precision = /*#__PURE__*/Object.freeze({
25689
- __proto__: null,
25690
- _internal: _internal,
25691
- to_bigint64: to_bigint64,
25692
- to_string64: to_string64
25693
- });
25694
-
25695
- const serializeTransaction = (transaction) => {
25696
- return Buffer.from(JSON.stringify(transaction));
25697
- };
25698
- const serializeOperation = (operation) => {
25699
- return Buffer.from(JSON.stringify(operation));
25700
- };
25701
- const getTransactionDigest = (transaction) => {
25702
- const serialized = serializeTransaction(transaction);
25703
- const serializedBuf = Buffer.isBuffer(serialized) ? serialized : Buffer.from(serialized);
25704
- return Buffer.from(sha256$2(serializedBuf));
25705
- };
25706
- const getTransactionId = (transaction) => {
25707
- const digest = getTransactionDigest(transaction);
25708
- return digest.toString('hex');
25709
- };
25710
- const serialize = (operation) => {
25711
- return Buffer.from(JSON.stringify(operation));
25712
- };
25713
- const deserialize = (buffer) => {
25714
- if (!buffer || buffer.length === 0)
25715
- return {};
25716
- return JSON.parse(buffer.toString());
25717
- };
25718
- const deserializeTransaction = (buffer) => {
25719
- if (!buffer || buffer.length === 0) {
25720
- return {
25721
- ref_block_num: 0,
25722
- ref_block_prefix: 0,
25723
- expiration: '',
25724
- operations: []
25725
- };
25726
- }
25727
- return JSON.parse(buffer.toString());
25728
- };
25729
-
25730
- const serializer = /*#__PURE__*/Object.freeze({
25731
- __proto__: null,
25732
- convert: convert,
25733
- deserialize: deserialize,
25734
- deserializeTransaction: deserializeTransaction,
25735
- getTransactionDigest: getTransactionDigest,
25736
- getTransactionId: getTransactionId,
25737
- precision: precision,
25738
- serialize: serialize,
25739
- serializeOperation: serializeOperation,
25740
- serializeTransaction: serializeTransaction,
25741
- types: types
25742
- });
25743
-
25744
26252
  const sha256 = (data) => {
25745
26253
  const input = Buffer.isBuffer(data) ? data : Buffer.from(data);
25746
26254
  return Buffer.from(sha256$2(input));
@@ -25815,9 +26323,8 @@ const steem = {
25815
26323
  formatter,
25816
26324
  memo,
25817
26325
  operations,
25818
- serializer,
25819
26326
  utils: utils$3,
25820
- version: '1.0.12',
26327
+ version: '1.0.14',
25821
26328
  config: {
25822
26329
  set: (options) => {
25823
26330
  // If nodes is provided, extract the first node as url for API