@steemit/steem-js 1.0.18 → 1.0.20

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
@@ -21973,11 +21973,25 @@ if (typeof BigInt === "function") {
21973
21973
  }
21974
21974
 
21975
21975
  /**
21976
- * Chain-safe JSON normalization for account_update operations.
21977
- * Matches steem::protocol::account_update_operation and authority (FC_REFLECT).
21978
- * Broadcast via JSON-RPC uses fc::from_variant; malformed shapes cause bad_cast_exception.
21976
+ * Chain-safe JSON normalization for `account_update` operations.
21977
+ *
21978
+ * Protocol types (steem/libraries/protocol):
21979
+ * - `authority` — weight_threshold (uint32), account_auths / key_auths (fc::flat_map)
21980
+ * - `account_update_operation` — account, optional owner/active/posting, memo_key, json_metadata (string)
21981
+ *
21982
+ * JSON-RPC (`condenser_api.broadcast_transaction` → fc::from_variant):
21983
+ * - `authority` is a variant_object, not a bare key_auths array.
21984
+ * - `fc::flat_map` serializes as an array of [key, weight] pairs (see fc/container/flat.hpp),
21985
+ * not a JSON object `{ "key": weight }` — object maps cause bad_cast_exception.
21986
+ * - `json_metadata` must be a string (protocol `string`), not a parsed JSON object.
21987
+ *
21988
+ * Binary signing (transaction digest) uses the same logical fields; the serializer packs
21989
+ * flat_maps as sorted on-wire maps (see serializeAuthority in serializer/transaction.ts).
21990
+ */
21991
+ /**
21992
+ * Coerce `json_metadata` to protocol `string` (FC string field).
21993
+ * Node rejects object/array variants with bad_cast when broadcasting.
21979
21994
  */
21980
- /** Steem broadcast JSON requires json_metadata to be a string (not object/array). */
21981
21995
  function normalizeChainJsonMetadata(value) {
21982
21996
  if (typeof value === 'string')
21983
21997
  return value;
@@ -21989,6 +22003,10 @@ function normalizeChainJsonMetadata(value) {
21989
22003
  return JSON.stringify(value);
21990
22004
  return String(value);
21991
22005
  }
22006
+ /**
22007
+ * Parse fc::flat_map JSON (pair array) or mistaken object-map input into pair arrays.
22008
+ * Broadcast output always uses pair arrays per fc::from_variant(flat_map).
22009
+ */
21992
22010
  function toAuthPairs(raw) {
21993
22011
  if (Array.isArray(raw)) {
21994
22012
  return raw
@@ -22017,7 +22035,7 @@ function toKeyAuthPairs(raw) {
22017
22035
  }
22018
22036
  return [];
22019
22037
  }
22020
- /** Normalize API authority data (handles object-maps and malformed arrays). */
22038
+ /** Normalize API authority data (get_accounts-style input; accepts pair arrays or object maps). */
22021
22039
  function normalizeAuthoritySource(source) {
22022
22040
  if (Array.isArray(source) || !source || typeof source !== 'object') {
22023
22041
  return { weight_threshold: 1, account_auths: [], key_auths: [] };
@@ -22043,7 +22061,10 @@ function sanitizeAuthority(value, field) {
22043
22061
  }
22044
22062
  return { weight_threshold, account_auths, key_auths };
22045
22063
  }
22046
- /** Coerce account_update operation payload to chain-safe JSON (for signing and broadcast). */
22064
+ /**
22065
+ * Coerce account_update operation payload to protocol JSON shape for signing and broadcast.
22066
+ * Emits fc::flat_map fields as pair arrays, not object maps.
22067
+ */
22047
22068
  function sanitizeAccountUpdatePayload(payload) {
22048
22069
  return {
22049
22070
  account: String(payload.account || ''),
@@ -22455,8 +22476,9 @@ function serializeAccountCreate(bb, data) {
22455
22476
  writeString(bb, String(dataObj.json_metadata || ''));
22456
22477
  }
22457
22478
  /**
22458
- * Serialize account_update operation.
22459
- * Format: account, optional owner (1 byte + authority?), optional active, optional posting, memo_key, json_metadata.
22479
+ * Serialize account_update_operation (steem_operations.hpp).
22480
+ * JSON fields: account, owner/active/posting (authority objects), memo_key, json_metadata (string).
22481
+ * Optional authorities use a presence byte before serializeAuthority.
22460
22482
  */
22461
22483
  function serializeAccountUpdate(bb, data) {
22462
22484
  const dataObj = data;
@@ -23123,7 +23145,26 @@ function serializeCustomJson(bb, data) {
23123
23145
  writeString(bb, String(dataObj.json || '{}'));
23124
23146
  }
23125
23147
  /**
23126
- * Serialize Authority
23148
+ * Read authority map fields for binary packing (on-wire sorted flat_map).
23149
+ * JSON-RPC uses fc::flat_map → array of [key, weight] pairs; object maps are accepted
23150
+ * here only so callers that forgot to normalize still sign the intended keys.
23151
+ */
23152
+ function authorityMapEntries(raw) {
23153
+ if (Array.isArray(raw)) {
23154
+ return raw
23155
+ .filter((entry) => Array.isArray(entry) && entry.length >= 2)
23156
+ .map(([key, weight]) => [String(key), Number(weight)])
23157
+ .filter(([, weight]) => Number.isFinite(weight));
23158
+ }
23159
+ if (raw && typeof raw === 'object') {
23160
+ return Object.entries(raw)
23161
+ .map(([key, weight]) => [String(key), Number(weight)])
23162
+ .filter(([, weight]) => Number.isFinite(weight));
23163
+ }
23164
+ return [];
23165
+ }
23166
+ /**
23167
+ * Serialize steem::protocol::authority (weight_threshold + sorted account/key flat_maps).
23127
23168
  */
23128
23169
  function serializeAuthority(bb, auth) {
23129
23170
  if (Array.isArray(auth)) {
@@ -23135,40 +23176,19 @@ function serializeAuthority(bb, auth) {
23135
23176
  const authObj = auth;
23136
23177
  bb.writeUint32(authObj.weight_threshold || 1);
23137
23178
  // Account auths (map<string, uint16>)
23138
- const accountAuths = (Array.isArray(authObj.account_auths) ? authObj.account_auths : []);
23139
- // Maps in Steem serialization are sorted by key
23140
- const accountAuthsArray = accountAuths;
23141
- accountAuthsArray.sort((a, b) => {
23142
- const aKey = Array.isArray(a) && a[0] ? String(a[0]) : '';
23143
- const bKey = Array.isArray(b) && b[0] ? String(b[0]) : '';
23144
- return aKey.localeCompare(bKey);
23145
- });
23179
+ const accountAuths = authorityMapEntries(authObj.account_auths).sort((a, b) => a[0].localeCompare(b[0]));
23146
23180
  bb.writeVarint32(accountAuths.length);
23147
- for (const authEntry of accountAuths) {
23148
- if (Array.isArray(authEntry) && authEntry.length >= 2) {
23149
- writeString(bb, String(authEntry[0]));
23150
- bb.writeUint16(authEntry[1]);
23151
- }
23181
+ for (const [account, weight] of accountAuths) {
23182
+ writeString(bb, account);
23183
+ bb.writeUint16(weight);
23152
23184
  }
23153
23185
  // Key auths (map<public_key, uint16>)
23154
- const keyAuths = (Array.isArray(authObj.key_auths) ? authObj.key_auths : []);
23155
- // Maps in Steem serialization are sorted by key (public key string)
23156
- // But serialized as bytes. Usually sorting by string representation of public key works.
23157
- const keyAuthsArray = keyAuths;
23158
- keyAuthsArray.sort((a, b) => {
23159
- const aKey = Array.isArray(a) && a[0] ? String(a[0]) : '';
23160
- const bKey = Array.isArray(b) && b[0] ? String(b[0]) : '';
23161
- return aKey.localeCompare(bKey);
23162
- });
23186
+ const keyAuths = authorityMapEntries(authObj.key_auths).sort((a, b) => a[0].localeCompare(b[0]));
23163
23187
  bb.writeVarint32(keyAuths.length);
23164
- for (const keyAuth of keyAuths) {
23165
- if (Array.isArray(keyAuth) && keyAuth.length >= 2) {
23166
- const keyStr = String(keyAuth[0]);
23167
- const weight = keyAuth[1];
23168
- const pubKey = PublicKey.fromStringOrThrow(keyStr);
23169
- bb.append(pubKey.toBuffer());
23170
- bb.writeUint16(weight);
23171
- }
23188
+ for (const [keyStr, weight] of keyAuths) {
23189
+ const pubKey = PublicKey.fromStringOrThrow(keyStr);
23190
+ bb.append(pubKey.toBuffer());
23191
+ bb.writeUint16(weight);
23172
23192
  }
23173
23193
  }
23174
23194
  /**
@@ -23508,18 +23528,34 @@ const verifySignature = (message, signature, publicKey) => {
23508
23528
  return false;
23509
23529
  }
23510
23530
  };
23531
+ // Serialize a transaction to its binary form for digest calculation.
23532
+ // Alias for transaction.toBuffer() so verifyTransaction mirrors signTransaction's
23533
+ // serialization path exactly (signTransaction calls transaction.toBuffer at line 161).
23534
+ const serializeTrx = (trx) => transaction.toBuffer(trx);
23511
23535
  const verifyTransaction = (transaction, publicKey) => {
23512
23536
  try {
23513
23537
  const pub = PublicKey.fromString(publicKey);
23514
23538
  if (!pub)
23515
23539
  return false;
23516
- const serialized = Buffer.from(JSON.stringify(transaction));
23517
23540
  const trx = transaction;
23518
23541
  if (!trx.signatures || !Array.isArray(trx.signatures))
23519
23542
  return false;
23543
+ // Reconstruct the exact digest signTransaction signs over:
23544
+ // Buffer.concat([chain_id, transaction.toBuffer(normalizedTrx)])
23545
+ // signatures are NOT part of the signed digest — signTransaction serializes
23546
+ // BEFORE attaching signatures — so strip them before serializing, otherwise
23547
+ // serializeTransaction() would emit the signatures array and change the digest.
23548
+ const normalizedTrx = normalizeTransactionForBroadcast(trx);
23549
+ // Build a copy without the signatures key, so serializeTransaction() does not
23550
+ // emit the signatures array into the digest (signTransaction serializes pre-signature).
23551
+ const trxWithoutSigs = { ...normalizedTrx };
23552
+ delete trxWithoutSigs.signatures;
23553
+ const chainId = getConfig().get('chain_id') || '';
23554
+ const cid = Buffer.from(chainId, 'hex');
23555
+ const buf = serializeTrx(trxWithoutSigs);
23520
23556
  return trx.signatures.some((sig) => {
23521
23557
  const signature = Signature.fromHex(sig);
23522
- return signature.verifyBuffer(serialized, pub);
23558
+ return signature.verifyBuffer(Buffer.concat([cid, buf]), pub);
23523
23559
  });
23524
23560
  }
23525
23561
  catch {
@@ -23564,6 +23600,7 @@ const auth = /*#__PURE__*/Object.freeze({
23564
23600
  normalizeTransactionForBroadcast: normalizeTransactionForBroadcast,
23565
23601
  resolveAuthorityForSerialize: resolveAuthorityForSerialize,
23566
23602
  sanitizeAccountUpdatePayload: sanitizeAccountUpdatePayload,
23603
+ serializeTransaction: serializeTransaction,
23567
23604
  sign: sign$1,
23568
23605
  signTransaction: signTransaction,
23569
23606
  toWif: toWif,
@@ -26372,7 +26409,7 @@ const steem = {
26372
26409
  memo,
26373
26410
  operations,
26374
26411
  utils: utils$3,
26375
- version: '1.0.18',
26412
+ version: '1.0.20',
26376
26413
  config: {
26377
26414
  set: (options) => {
26378
26415
  // If nodes is provided, extract the first node as url for API