@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.umd.js CHANGED
@@ -24987,11 +24987,25 @@
24987
24987
  }
24988
24988
 
24989
24989
  /**
24990
- * Chain-safe JSON normalization for account_update operations.
24991
- * Matches steem::protocol::account_update_operation and authority (FC_REFLECT).
24992
- * Broadcast via JSON-RPC uses fc::from_variant; malformed shapes cause bad_cast_exception.
24990
+ * Chain-safe JSON normalization for `account_update` operations.
24991
+ *
24992
+ * Protocol types (steem/libraries/protocol):
24993
+ * - `authority` — weight_threshold (uint32), account_auths / key_auths (fc::flat_map)
24994
+ * - `account_update_operation` — account, optional owner/active/posting, memo_key, json_metadata (string)
24995
+ *
24996
+ * JSON-RPC (`condenser_api.broadcast_transaction` → fc::from_variant):
24997
+ * - `authority` is a variant_object, not a bare key_auths array.
24998
+ * - `fc::flat_map` serializes as an array of [key, weight] pairs (see fc/container/flat.hpp),
24999
+ * not a JSON object `{ "key": weight }` — object maps cause bad_cast_exception.
25000
+ * - `json_metadata` must be a string (protocol `string`), not a parsed JSON object.
25001
+ *
25002
+ * Binary signing (transaction digest) uses the same logical fields; the serializer packs
25003
+ * flat_maps as sorted on-wire maps (see serializeAuthority in serializer/transaction.ts).
25004
+ */
25005
+ /**
25006
+ * Coerce `json_metadata` to protocol `string` (FC string field).
25007
+ * Node rejects object/array variants with bad_cast when broadcasting.
24993
25008
  */
24994
- /** Steem broadcast JSON requires json_metadata to be a string (not object/array). */
24995
25009
  function normalizeChainJsonMetadata(value) {
24996
25010
  if (typeof value === 'string')
24997
25011
  return value;
@@ -25003,6 +25017,10 @@
25003
25017
  return JSON.stringify(value);
25004
25018
  return String(value);
25005
25019
  }
25020
+ /**
25021
+ * Parse fc::flat_map JSON (pair array) or mistaken object-map input into pair arrays.
25022
+ * Broadcast output always uses pair arrays per fc::from_variant(flat_map).
25023
+ */
25006
25024
  function toAuthPairs(raw) {
25007
25025
  if (Array.isArray(raw)) {
25008
25026
  return raw
@@ -25031,7 +25049,7 @@
25031
25049
  }
25032
25050
  return [];
25033
25051
  }
25034
- /** Normalize API authority data (handles object-maps and malformed arrays). */
25052
+ /** Normalize API authority data (get_accounts-style input; accepts pair arrays or object maps). */
25035
25053
  function normalizeAuthoritySource(source) {
25036
25054
  if (Array.isArray(source) || !source || typeof source !== 'object') {
25037
25055
  return { weight_threshold: 1, account_auths: [], key_auths: [] };
@@ -25057,7 +25075,10 @@
25057
25075
  }
25058
25076
  return { weight_threshold, account_auths, key_auths };
25059
25077
  }
25060
- /** Coerce account_update operation payload to chain-safe JSON (for signing and broadcast). */
25078
+ /**
25079
+ * Coerce account_update operation payload to protocol JSON shape for signing and broadcast.
25080
+ * Emits fc::flat_map fields as pair arrays, not object maps.
25081
+ */
25061
25082
  function sanitizeAccountUpdatePayload(payload) {
25062
25083
  return {
25063
25084
  account: String(payload.account || ''),
@@ -25469,8 +25490,9 @@
25469
25490
  writeString(bb, String(dataObj.json_metadata || ''));
25470
25491
  }
25471
25492
  /**
25472
- * Serialize account_update operation.
25473
- * Format: account, optional owner (1 byte + authority?), optional active, optional posting, memo_key, json_metadata.
25493
+ * Serialize account_update_operation (steem_operations.hpp).
25494
+ * JSON fields: account, owner/active/posting (authority objects), memo_key, json_metadata (string).
25495
+ * Optional authorities use a presence byte before serializeAuthority.
25474
25496
  */
25475
25497
  function serializeAccountUpdate(bb, data) {
25476
25498
  const dataObj = data;
@@ -26137,7 +26159,26 @@
26137
26159
  writeString(bb, String(dataObj.json || '{}'));
26138
26160
  }
26139
26161
  /**
26140
- * Serialize Authority
26162
+ * Read authority map fields for binary packing (on-wire sorted flat_map).
26163
+ * JSON-RPC uses fc::flat_map → array of [key, weight] pairs; object maps are accepted
26164
+ * here only so callers that forgot to normalize still sign the intended keys.
26165
+ */
26166
+ function authorityMapEntries(raw) {
26167
+ if (Array.isArray(raw)) {
26168
+ return raw
26169
+ .filter((entry) => Array.isArray(entry) && entry.length >= 2)
26170
+ .map(([key, weight]) => [String(key), Number(weight)])
26171
+ .filter(([, weight]) => Number.isFinite(weight));
26172
+ }
26173
+ if (raw && typeof raw === 'object') {
26174
+ return Object.entries(raw)
26175
+ .map(([key, weight]) => [String(key), Number(weight)])
26176
+ .filter(([, weight]) => Number.isFinite(weight));
26177
+ }
26178
+ return [];
26179
+ }
26180
+ /**
26181
+ * Serialize steem::protocol::authority (weight_threshold + sorted account/key flat_maps).
26141
26182
  */
26142
26183
  function serializeAuthority(bb, auth) {
26143
26184
  if (Array.isArray(auth)) {
@@ -26149,40 +26190,19 @@
26149
26190
  const authObj = auth;
26150
26191
  bb.writeUint32(authObj.weight_threshold || 1);
26151
26192
  // Account auths (map<string, uint16>)
26152
- const accountAuths = (Array.isArray(authObj.account_auths) ? authObj.account_auths : []);
26153
- // Maps in Steem serialization are sorted by key
26154
- const accountAuthsArray = accountAuths;
26155
- accountAuthsArray.sort((a, b) => {
26156
- const aKey = Array.isArray(a) && a[0] ? String(a[0]) : '';
26157
- const bKey = Array.isArray(b) && b[0] ? String(b[0]) : '';
26158
- return aKey.localeCompare(bKey);
26159
- });
26193
+ const accountAuths = authorityMapEntries(authObj.account_auths).sort((a, b) => a[0].localeCompare(b[0]));
26160
26194
  bb.writeVarint32(accountAuths.length);
26161
- for (const authEntry of accountAuths) {
26162
- if (Array.isArray(authEntry) && authEntry.length >= 2) {
26163
- writeString(bb, String(authEntry[0]));
26164
- bb.writeUint16(authEntry[1]);
26165
- }
26195
+ for (const [account, weight] of accountAuths) {
26196
+ writeString(bb, account);
26197
+ bb.writeUint16(weight);
26166
26198
  }
26167
26199
  // Key auths (map<public_key, uint16>)
26168
- const keyAuths = (Array.isArray(authObj.key_auths) ? authObj.key_auths : []);
26169
- // Maps in Steem serialization are sorted by key (public key string)
26170
- // But serialized as bytes. Usually sorting by string representation of public key works.
26171
- const keyAuthsArray = keyAuths;
26172
- keyAuthsArray.sort((a, b) => {
26173
- const aKey = Array.isArray(a) && a[0] ? String(a[0]) : '';
26174
- const bKey = Array.isArray(b) && b[0] ? String(b[0]) : '';
26175
- return aKey.localeCompare(bKey);
26176
- });
26200
+ const keyAuths = authorityMapEntries(authObj.key_auths).sort((a, b) => a[0].localeCompare(b[0]));
26177
26201
  bb.writeVarint32(keyAuths.length);
26178
- for (const keyAuth of keyAuths) {
26179
- if (Array.isArray(keyAuth) && keyAuth.length >= 2) {
26180
- const keyStr = String(keyAuth[0]);
26181
- const weight = keyAuth[1];
26182
- const pubKey = PublicKey.fromStringOrThrow(keyStr);
26183
- bb.append(pubKey.toBuffer());
26184
- bb.writeUint16(weight);
26185
- }
26202
+ for (const [keyStr, weight] of keyAuths) {
26203
+ const pubKey = PublicKey.fromStringOrThrow(keyStr);
26204
+ bb.append(pubKey.toBuffer());
26205
+ bb.writeUint16(weight);
26186
26206
  }
26187
26207
  }
26188
26208
  /**
@@ -26522,18 +26542,34 @@
26522
26542
  return false;
26523
26543
  }
26524
26544
  };
26545
+ // Serialize a transaction to its binary form for digest calculation.
26546
+ // Alias for transaction.toBuffer() so verifyTransaction mirrors signTransaction's
26547
+ // serialization path exactly (signTransaction calls transaction.toBuffer at line 161).
26548
+ const serializeTrx = (trx) => transaction.toBuffer(trx);
26525
26549
  const verifyTransaction = (transaction, publicKey) => {
26526
26550
  try {
26527
26551
  const pub = PublicKey.fromString(publicKey);
26528
26552
  if (!pub)
26529
26553
  return false;
26530
- const serialized = buffer.Buffer.from(JSON.stringify(transaction));
26531
26554
  const trx = transaction;
26532
26555
  if (!trx.signatures || !Array.isArray(trx.signatures))
26533
26556
  return false;
26557
+ // Reconstruct the exact digest signTransaction signs over:
26558
+ // Buffer.concat([chain_id, transaction.toBuffer(normalizedTrx)])
26559
+ // signatures are NOT part of the signed digest — signTransaction serializes
26560
+ // BEFORE attaching signatures — so strip them before serializing, otherwise
26561
+ // serializeTransaction() would emit the signatures array and change the digest.
26562
+ const normalizedTrx = normalizeTransactionForBroadcast(trx);
26563
+ // Build a copy without the signatures key, so serializeTransaction() does not
26564
+ // emit the signatures array into the digest (signTransaction serializes pre-signature).
26565
+ const trxWithoutSigs = { ...normalizedTrx };
26566
+ delete trxWithoutSigs.signatures;
26567
+ const chainId = getConfig().get('chain_id') || '';
26568
+ const cid = buffer.Buffer.from(chainId, 'hex');
26569
+ const buf = serializeTrx(trxWithoutSigs);
26534
26570
  return trx.signatures.some((sig) => {
26535
26571
  const signature = Signature.fromHex(sig);
26536
- return signature.verifyBuffer(serialized, pub);
26572
+ return signature.verifyBuffer(buffer.Buffer.concat([cid, buf]), pub);
26537
26573
  });
26538
26574
  }
26539
26575
  catch {
@@ -26578,6 +26614,7 @@
26578
26614
  normalizeTransactionForBroadcast: normalizeTransactionForBroadcast,
26579
26615
  resolveAuthorityForSerialize: resolveAuthorityForSerialize,
26580
26616
  sanitizeAccountUpdatePayload: sanitizeAccountUpdatePayload,
26617
+ serializeTransaction: serializeTransaction,
26581
26618
  sign: sign$1,
26582
26619
  signTransaction: signTransaction,
26583
26620
  toWif: toWif,
@@ -29399,7 +29436,7 @@
29399
29436
  operations,
29400
29437
  utils: utils$n,
29401
29438
  ...crypto$1,
29402
- version: '1.0.18',
29439
+ version: '1.0.20',
29403
29440
  config: {
29404
29441
  set: (options) => {
29405
29442
  // If nodes is provided, extract the first node as url for API