@steemit/steem-js 1.0.0 → 1.0.1
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/auth/serializer/transaction.d.ts +5 -0
- package/dist/config.d.ts +2 -0
- package/dist/index.cjs +618 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +620 -32
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +636 -28
- package/dist/index.umd.js.map +1 -1
- package/dist/utils/debug.d.ts +36 -0
- package/dist/utils/index.d.ts +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import * as assert from 'assert';
|
|
|
5
5
|
import assert__default from 'assert';
|
|
6
6
|
import * as buffer from 'buffer';
|
|
7
7
|
import * as crypto from 'crypto';
|
|
8
|
-
import { randomBytes, createHash as createHash$2, createCipheriv, createDecipheriv, createHmac as createHmac$
|
|
8
|
+
import { randomBytes, createHash as createHash$2, createCipheriv, createDecipheriv, createHmac as createHmac$2 } from 'crypto';
|
|
9
9
|
import axios from 'axios';
|
|
10
10
|
import * as https from 'https';
|
|
11
11
|
import * as http from 'http';
|
|
@@ -6056,6 +6056,98 @@ const setConfig = (newConfig) => {
|
|
|
6056
6056
|
// Alias for setConfig to match the API's setOptions
|
|
6057
6057
|
const setOptions$1 = setConfig;
|
|
6058
6058
|
|
|
6059
|
+
const config$1 = /*#__PURE__*/Object.freeze({
|
|
6060
|
+
__proto__: null,
|
|
6061
|
+
Config: Config,
|
|
6062
|
+
getConfig: getConfig,
|
|
6063
|
+
setConfig: setConfig,
|
|
6064
|
+
setOptions: setOptions$1
|
|
6065
|
+
});
|
|
6066
|
+
|
|
6067
|
+
/**
|
|
6068
|
+
* Debug utility for controlled debug output
|
|
6069
|
+
* Can be enabled via:
|
|
6070
|
+
* 1. Config: steem.config.set({ debug: true })
|
|
6071
|
+
* 2. Environment variable: DEBUG=steem-js or DEBUG=steem-js:*
|
|
6072
|
+
* 3. Specific debug flags: DEBUG=steem-js:transaction,steem-js:signature
|
|
6073
|
+
*/
|
|
6074
|
+
// Check if debug is enabled via environment variable
|
|
6075
|
+
const DEBUG_ENV = process.env.DEBUG || '';
|
|
6076
|
+
const DEBUG_ENABLED = DEBUG_ENV.includes('steem-js');
|
|
6077
|
+
// Parse debug flags from environment
|
|
6078
|
+
const DEBUG_FLAGS = DEBUG_ENV.split(',').map(f => f.trim());
|
|
6079
|
+
function isDebugEnabled(flag) {
|
|
6080
|
+
// Check config first
|
|
6081
|
+
const configDebug = getConfig().get('debug');
|
|
6082
|
+
if (configDebug === true) {
|
|
6083
|
+
return true;
|
|
6084
|
+
}
|
|
6085
|
+
if (configDebug === false) {
|
|
6086
|
+
return false;
|
|
6087
|
+
}
|
|
6088
|
+
// Check environment variable
|
|
6089
|
+
if (!DEBUG_ENABLED) {
|
|
6090
|
+
return false;
|
|
6091
|
+
}
|
|
6092
|
+
// If no flag specified, check for general steem-js debug
|
|
6093
|
+
if (!flag) {
|
|
6094
|
+
return DEBUG_ENV.includes('steem-js') && !DEBUG_ENV.includes('steem-js:');
|
|
6095
|
+
}
|
|
6096
|
+
// Check for specific flag
|
|
6097
|
+
const flagPattern = `steem-js:${flag}`;
|
|
6098
|
+
return DEBUG_FLAGS.some(f => f === flagPattern || f === 'steem-js:*');
|
|
6099
|
+
}
|
|
6100
|
+
const debug = {
|
|
6101
|
+
/**
|
|
6102
|
+
* Log debug information
|
|
6103
|
+
* @param flag - Optional debug flag (e.g., 'transaction', 'signature')
|
|
6104
|
+
* @param args - Arguments to log
|
|
6105
|
+
*/
|
|
6106
|
+
log(flag, ...args) {
|
|
6107
|
+
if (isDebugEnabled(flag)) {
|
|
6108
|
+
const prefix = flag ? `[steem-js:${flag}]` : '[steem-js]';
|
|
6109
|
+
console.log(prefix, ...args);
|
|
6110
|
+
}
|
|
6111
|
+
},
|
|
6112
|
+
/**
|
|
6113
|
+
* Log transaction debug info
|
|
6114
|
+
*/
|
|
6115
|
+
transaction(...args) {
|
|
6116
|
+
this.log('transaction', ...args);
|
|
6117
|
+
},
|
|
6118
|
+
/**
|
|
6119
|
+
* Log signature debug info
|
|
6120
|
+
*/
|
|
6121
|
+
signature(...args) {
|
|
6122
|
+
this.log('signature', ...args);
|
|
6123
|
+
},
|
|
6124
|
+
/**
|
|
6125
|
+
* Log warning (always shown, but can be controlled)
|
|
6126
|
+
*/
|
|
6127
|
+
warn(...args) {
|
|
6128
|
+
if (isDebugEnabled() || getConfig().get('debug_warnings') !== false) {
|
|
6129
|
+
console.warn('[steem-js]', ...args);
|
|
6130
|
+
}
|
|
6131
|
+
},
|
|
6132
|
+
/**
|
|
6133
|
+
* Log error (always shown)
|
|
6134
|
+
*/
|
|
6135
|
+
error(...args) {
|
|
6136
|
+
console.error('[steem-js]', ...args);
|
|
6137
|
+
},
|
|
6138
|
+
/**
|
|
6139
|
+
* Check if debug is enabled for a specific flag
|
|
6140
|
+
*/
|
|
6141
|
+
isEnabled(flag) {
|
|
6142
|
+
return isDebugEnabled(flag);
|
|
6143
|
+
}
|
|
6144
|
+
};
|
|
6145
|
+
|
|
6146
|
+
const debug$1 = /*#__PURE__*/Object.freeze({
|
|
6147
|
+
__proto__: null,
|
|
6148
|
+
debug: debug
|
|
6149
|
+
});
|
|
6150
|
+
|
|
6059
6151
|
const sleep = (ms) => {
|
|
6060
6152
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
6061
6153
|
};
|
|
@@ -6101,6 +6193,7 @@ const utils = /*#__PURE__*/Object.freeze({
|
|
|
6101
6193
|
__proto__: null,
|
|
6102
6194
|
camelCase: camelCase,
|
|
6103
6195
|
chunk: chunk,
|
|
6196
|
+
debug: debug,
|
|
6104
6197
|
flatten: flatten,
|
|
6105
6198
|
isValidAddress: isValidAddress,
|
|
6106
6199
|
isValidAmount: isValidAmount,
|
|
@@ -8281,17 +8374,18 @@ function requireCreateHash () {
|
|
|
8281
8374
|
var createHashExports = requireCreateHash();
|
|
8282
8375
|
const createHash = /*@__PURE__*/getDefaultExportFromCjs(createHashExports);
|
|
8283
8376
|
|
|
8284
|
-
var createHmac;
|
|
8377
|
+
var createHmac$1;
|
|
8285
8378
|
var hasRequiredCreateHmac;
|
|
8286
8379
|
|
|
8287
8380
|
function requireCreateHmac () {
|
|
8288
|
-
if (hasRequiredCreateHmac) return createHmac;
|
|
8381
|
+
if (hasRequiredCreateHmac) return createHmac$1;
|
|
8289
8382
|
hasRequiredCreateHmac = 1;
|
|
8290
|
-
createHmac = require$$3$1.createHmac;
|
|
8291
|
-
return createHmac;
|
|
8383
|
+
createHmac$1 = require$$3$1.createHmac;
|
|
8384
|
+
return createHmac$1;
|
|
8292
8385
|
}
|
|
8293
8386
|
|
|
8294
|
-
requireCreateHmac();
|
|
8387
|
+
var createHmacExports = requireCreateHmac();
|
|
8388
|
+
const createHmac = /*@__PURE__*/getDefaultExportFromCjs(createHmacExports);
|
|
8295
8389
|
|
|
8296
8390
|
/** @arg {string|Buffer} data
|
|
8297
8391
|
@arg {string} [digest = null] - 'hex', 'binary' or 'base64'
|
|
@@ -8313,6 +8407,9 @@ function sha512(data, encoding) {
|
|
|
8313
8407
|
}
|
|
8314
8408
|
return createHash('sha512').update(data).digest();
|
|
8315
8409
|
}
|
|
8410
|
+
function HmacSHA256(buffer, secret) {
|
|
8411
|
+
return createHmac('sha256', secret).update(buffer).digest();
|
|
8412
|
+
}
|
|
8316
8413
|
function ripemd160$1(data) {
|
|
8317
8414
|
return createHash('rmd160').update(data).digest();
|
|
8318
8415
|
}
|
|
@@ -8598,7 +8695,7 @@ class PrivateKey {
|
|
|
8598
8695
|
throw new Error("Expecting parameter to be a Buffer type");
|
|
8599
8696
|
}
|
|
8600
8697
|
if (32 !== buf.length) {
|
|
8601
|
-
|
|
8698
|
+
debug.warn(`WARN: Expecting 32 bytes, instead got ${buf.length}, stack trace:`, new Error().stack);
|
|
8602
8699
|
}
|
|
8603
8700
|
if (buf.length === 0) {
|
|
8604
8701
|
throw new Error("Empty buffer");
|
|
@@ -8717,6 +8814,278 @@ const toPublic = (data) => {
|
|
|
8717
8814
|
return data;
|
|
8718
8815
|
};
|
|
8719
8816
|
|
|
8817
|
+
function enforce(type, value) {
|
|
8818
|
+
switch (type) {
|
|
8819
|
+
case 'Array': {
|
|
8820
|
+
if (Array.isArray(value))
|
|
8821
|
+
return;
|
|
8822
|
+
break;
|
|
8823
|
+
}
|
|
8824
|
+
case 'Boolean': {
|
|
8825
|
+
if (typeof value === 'boolean')
|
|
8826
|
+
return;
|
|
8827
|
+
break;
|
|
8828
|
+
}
|
|
8829
|
+
case 'Buffer': {
|
|
8830
|
+
if (Buffer.isBuffer(value))
|
|
8831
|
+
return;
|
|
8832
|
+
break;
|
|
8833
|
+
}
|
|
8834
|
+
case 'Number': {
|
|
8835
|
+
if (typeof value === 'number')
|
|
8836
|
+
return;
|
|
8837
|
+
break;
|
|
8838
|
+
}
|
|
8839
|
+
case 'String': {
|
|
8840
|
+
if (typeof value === 'string')
|
|
8841
|
+
return;
|
|
8842
|
+
break;
|
|
8843
|
+
}
|
|
8844
|
+
default: {
|
|
8845
|
+
if (typeof type === 'function' && getName(value.constructor) === getName(type))
|
|
8846
|
+
return;
|
|
8847
|
+
}
|
|
8848
|
+
}
|
|
8849
|
+
throw new TypeError('Expected ' + (typeof type === 'function' ? getName(type) : type) + ', got ' + value);
|
|
8850
|
+
}
|
|
8851
|
+
function getName(fn) {
|
|
8852
|
+
const match = fn.toString().match(/function (.*?)\(/);
|
|
8853
|
+
return match ? match[1] : null;
|
|
8854
|
+
}
|
|
8855
|
+
|
|
8856
|
+
class ECSignature {
|
|
8857
|
+
constructor(r, s) {
|
|
8858
|
+
enforce(bigi, r);
|
|
8859
|
+
enforce(bigi, s);
|
|
8860
|
+
this.r = r;
|
|
8861
|
+
this.s = s;
|
|
8862
|
+
}
|
|
8863
|
+
static parseCompact(buffer) {
|
|
8864
|
+
if (buffer.length !== 65)
|
|
8865
|
+
throw new Error('Invalid signature length');
|
|
8866
|
+
let i = buffer.readUInt8(0) - 27;
|
|
8867
|
+
if ((i & 7) !== i)
|
|
8868
|
+
throw new Error('Invalid signature parameter');
|
|
8869
|
+
const compressed = !!(i & 4);
|
|
8870
|
+
i = i & 3;
|
|
8871
|
+
const r = bigi.fromBuffer(buffer.slice(1, 33));
|
|
8872
|
+
const s = bigi.fromBuffer(buffer.slice(33));
|
|
8873
|
+
return {
|
|
8874
|
+
compressed,
|
|
8875
|
+
i,
|
|
8876
|
+
signature: new ECSignature(r, s)
|
|
8877
|
+
};
|
|
8878
|
+
}
|
|
8879
|
+
static fromDER(buffer) {
|
|
8880
|
+
if (buffer.readUInt8(0) !== 0x30)
|
|
8881
|
+
throw new Error('Not a DER sequence');
|
|
8882
|
+
if (buffer.readUInt8(1) !== buffer.length - 2)
|
|
8883
|
+
throw new Error('Invalid sequence length');
|
|
8884
|
+
if (buffer.readUInt8(2) !== 0x02)
|
|
8885
|
+
throw new Error('Expected a DER integer');
|
|
8886
|
+
const rLen = buffer.readUInt8(3);
|
|
8887
|
+
if (rLen === 0)
|
|
8888
|
+
throw new Error('R length is zero');
|
|
8889
|
+
let offset = 4 + rLen;
|
|
8890
|
+
if (buffer.readUInt8(offset) !== 0x02)
|
|
8891
|
+
throw new Error('Expected a DER integer (2)');
|
|
8892
|
+
const sLen = buffer.readUInt8(offset + 1);
|
|
8893
|
+
if (sLen === 0)
|
|
8894
|
+
throw new Error('S length is zero');
|
|
8895
|
+
const rB = buffer.slice(4, offset);
|
|
8896
|
+
const sB = buffer.slice(offset + 2);
|
|
8897
|
+
offset += 2 + sLen;
|
|
8898
|
+
if (rLen > 1 && rB.readUInt8(0) === 0x00) {
|
|
8899
|
+
if (!(rB.readUInt8(1) & 0x80))
|
|
8900
|
+
throw new Error('R value excessively padded');
|
|
8901
|
+
}
|
|
8902
|
+
if (sLen > 1 && sB.readUInt8(0) === 0x00) {
|
|
8903
|
+
if (!(sB.readUInt8(1) & 0x80))
|
|
8904
|
+
throw new Error('S value excessively padded');
|
|
8905
|
+
}
|
|
8906
|
+
if (offset !== buffer.length)
|
|
8907
|
+
throw new Error('Invalid DER encoding');
|
|
8908
|
+
const r = bigi.fromBuffer(rB);
|
|
8909
|
+
const s = bigi.fromBuffer(sB);
|
|
8910
|
+
if (r.signum() < 0)
|
|
8911
|
+
throw new Error('R value is negative');
|
|
8912
|
+
if (s.signum() < 0)
|
|
8913
|
+
throw new Error('S value is negative');
|
|
8914
|
+
return new ECSignature(r, s);
|
|
8915
|
+
}
|
|
8916
|
+
static parseScriptSignature(buffer) {
|
|
8917
|
+
const hashType = buffer.readUInt8(buffer.length - 1);
|
|
8918
|
+
const hashTypeMod = hashType & -129;
|
|
8919
|
+
if (hashTypeMod <= 0x00 || hashTypeMod >= 0x04)
|
|
8920
|
+
throw new Error('Invalid hashType');
|
|
8921
|
+
return {
|
|
8922
|
+
signature: ECSignature.fromDER(buffer.slice(0, -1)),
|
|
8923
|
+
hashType
|
|
8924
|
+
};
|
|
8925
|
+
}
|
|
8926
|
+
toCompact(i, compressed) {
|
|
8927
|
+
if (compressed)
|
|
8928
|
+
i += 4;
|
|
8929
|
+
i += 27;
|
|
8930
|
+
const buffer = Buffer.alloc(65);
|
|
8931
|
+
buffer.writeUInt8(i, 0);
|
|
8932
|
+
this.r.toBuffer(32).copy(buffer, 1);
|
|
8933
|
+
this.s.toBuffer(32).copy(buffer, 33);
|
|
8934
|
+
return buffer;
|
|
8935
|
+
}
|
|
8936
|
+
toDER() {
|
|
8937
|
+
const rBa = this.r.toBuffer();
|
|
8938
|
+
const sBa = this.s.toBuffer();
|
|
8939
|
+
const sequence = [];
|
|
8940
|
+
// INTEGER
|
|
8941
|
+
sequence.push(0x02, rBa.length);
|
|
8942
|
+
Array.from(rBa).forEach(b => sequence.push(b));
|
|
8943
|
+
// INTEGER
|
|
8944
|
+
sequence.push(0x02, sBa.length);
|
|
8945
|
+
Array.from(sBa).forEach(b => sequence.push(b));
|
|
8946
|
+
// SEQUENCE
|
|
8947
|
+
sequence.unshift(0x30, sequence.length);
|
|
8948
|
+
return Buffer.from(sequence);
|
|
8949
|
+
}
|
|
8950
|
+
toScriptSignature(hashType) {
|
|
8951
|
+
const hashTypeBuffer = Buffer.alloc(1);
|
|
8952
|
+
hashTypeBuffer.writeUInt8(hashType, 0);
|
|
8953
|
+
return Buffer.concat([this.toDER(), hashTypeBuffer]);
|
|
8954
|
+
}
|
|
8955
|
+
}
|
|
8956
|
+
|
|
8957
|
+
// https://tools.ietf.org/html/rfc6979#section-3.2
|
|
8958
|
+
function deterministicGenerateK(curve, hash, d, checkSig, nonce) {
|
|
8959
|
+
enforce('Buffer', hash);
|
|
8960
|
+
enforce(bigi, d);
|
|
8961
|
+
if (nonce) {
|
|
8962
|
+
hash = sha256$1(Buffer.concat([hash, Buffer.alloc(nonce)]));
|
|
8963
|
+
}
|
|
8964
|
+
// sanity check
|
|
8965
|
+
assert__default.equal(hash.length, 32, 'Hash must be 256 bit');
|
|
8966
|
+
const x = d.toBuffer(32);
|
|
8967
|
+
let k = Buffer.alloc(32);
|
|
8968
|
+
let v = Buffer.alloc(32);
|
|
8969
|
+
// Step B
|
|
8970
|
+
v.fill(1);
|
|
8971
|
+
// Step C
|
|
8972
|
+
k.fill(0);
|
|
8973
|
+
// Step D
|
|
8974
|
+
k = HmacSHA256(Buffer.concat([v, Buffer.from([0]), x, hash]), k);
|
|
8975
|
+
// Step E
|
|
8976
|
+
v = HmacSHA256(v, k);
|
|
8977
|
+
// Step F
|
|
8978
|
+
k = HmacSHA256(Buffer.concat([v, Buffer.from([1]), x, hash]), k);
|
|
8979
|
+
// Step G
|
|
8980
|
+
v = HmacSHA256(v, k);
|
|
8981
|
+
// Step H1/H2a, ignored as tlen === qlen (256 bit)
|
|
8982
|
+
// Step H2b
|
|
8983
|
+
v = HmacSHA256(v, k);
|
|
8984
|
+
let T = bigi.fromBuffer(v);
|
|
8985
|
+
// Step H3, repeat until T is within the interval [1, n - 1] and passes the supplied check
|
|
8986
|
+
while ((T.signum() <= 0) || (T.compareTo(curve.n) >= 0) || !checkSig(T)) {
|
|
8987
|
+
k = HmacSHA256(Buffer.concat([v, Buffer.from([0])]), k);
|
|
8988
|
+
v = HmacSHA256(v, k);
|
|
8989
|
+
// Step H1/H2a, again, ignored as tlen === qlen (256 bit)
|
|
8990
|
+
// Step H2b again
|
|
8991
|
+
v = HmacSHA256(v, k);
|
|
8992
|
+
T = bigi.fromBuffer(v);
|
|
8993
|
+
}
|
|
8994
|
+
return T;
|
|
8995
|
+
}
|
|
8996
|
+
function sign$3(curve, hash, d, nonce) {
|
|
8997
|
+
const e = bigi.fromBuffer(hash);
|
|
8998
|
+
const n = curve.n;
|
|
8999
|
+
const G = curve.G;
|
|
9000
|
+
let r;
|
|
9001
|
+
let s;
|
|
9002
|
+
deterministicGenerateK(curve, hash, d, function (k) {
|
|
9003
|
+
// find canonically valid signature
|
|
9004
|
+
const Q = G.multiply(k);
|
|
9005
|
+
if (curve.isInfinity(Q))
|
|
9006
|
+
return false;
|
|
9007
|
+
const tempR = Q.affineX.mod(n);
|
|
9008
|
+
if (tempR.signum() === 0)
|
|
9009
|
+
return false;
|
|
9010
|
+
const tempS = k.modInverse(n).multiply(e.add(d.multiply(tempR))).mod(n);
|
|
9011
|
+
if (tempS.signum() === 0)
|
|
9012
|
+
return false;
|
|
9013
|
+
r = tempR;
|
|
9014
|
+
s = tempS;
|
|
9015
|
+
return true;
|
|
9016
|
+
}, nonce);
|
|
9017
|
+
if (!r || !s)
|
|
9018
|
+
throw new Error('Unable to find valid signature');
|
|
9019
|
+
const N_OVER_TWO = n.shiftRight(1);
|
|
9020
|
+
// enforce low S values, see bip62: 'low s values in signatures'
|
|
9021
|
+
const finalS = s.compareTo(N_OVER_TWO) > 0 ? n.subtract(s) : s;
|
|
9022
|
+
return new ECSignature(r, finalS);
|
|
9023
|
+
}
|
|
9024
|
+
/**
|
|
9025
|
+
* Recover a public key from a signature.
|
|
9026
|
+
*
|
|
9027
|
+
* See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public
|
|
9028
|
+
* Key Recovery Operation".
|
|
9029
|
+
*
|
|
9030
|
+
* http://www.secg.org/download/aid-780/sec1-v2.pdf
|
|
9031
|
+
*/
|
|
9032
|
+
function recoverPubKey(curve, e, signature, i) {
|
|
9033
|
+
assert__default.strictEqual(i & 3, i, 'Recovery param is more than two bits');
|
|
9034
|
+
const n = curve.n;
|
|
9035
|
+
const G = curve.G;
|
|
9036
|
+
const r = signature.r;
|
|
9037
|
+
const s = signature.s;
|
|
9038
|
+
assert__default(r.signum() > 0 && r.compareTo(n) < 0, 'Invalid r value');
|
|
9039
|
+
assert__default(s.signum() > 0 && s.compareTo(n) < 0, 'Invalid s value');
|
|
9040
|
+
// A set LSB signifies that the y-coordinate is odd
|
|
9041
|
+
const isYOdd = !!(i & 1);
|
|
9042
|
+
// The more significant bit specifies whether we should use the
|
|
9043
|
+
// first or second candidate key.
|
|
9044
|
+
const isSecondKey = i >> 1;
|
|
9045
|
+
// 1.1 Let x = r + jn
|
|
9046
|
+
const x = isSecondKey ? r.add(n) : r;
|
|
9047
|
+
const R = curve.pointFromX(isYOdd, x);
|
|
9048
|
+
// 1.4 Check that nR is at infinity
|
|
9049
|
+
const nR = R.multiply(n);
|
|
9050
|
+
assert__default(curve.isInfinity(nR), 'nR is not a valid curve point');
|
|
9051
|
+
// Compute -e from e
|
|
9052
|
+
const eNeg = e.negate().mod(n);
|
|
9053
|
+
// 1.6.1 Compute Q = r^-1 (sR - eG)
|
|
9054
|
+
// Q = r^-1 (sR + -eG)
|
|
9055
|
+
const rInv = r.modInverse(n);
|
|
9056
|
+
const sR = R.multiply(s);
|
|
9057
|
+
const eGNeg = G.multiply(eNeg);
|
|
9058
|
+
const Q = sR.add(eGNeg).multiply(rInv);
|
|
9059
|
+
curve.validate(Q);
|
|
9060
|
+
return Q;
|
|
9061
|
+
}
|
|
9062
|
+
/**
|
|
9063
|
+
* Calculate pubkey extraction parameter.
|
|
9064
|
+
*
|
|
9065
|
+
* When extracting a pubkey from a signature, we have to
|
|
9066
|
+
* distinguish four different cases. Rather than putting this
|
|
9067
|
+
* burden on the verifier, Bitcoin includes a 2-bit value with the
|
|
9068
|
+
* signature.
|
|
9069
|
+
*
|
|
9070
|
+
* This function simply tries all four cases and returns the value
|
|
9071
|
+
* that resulted in a successful pubkey recovery.
|
|
9072
|
+
*/
|
|
9073
|
+
function calcPubKeyRecoveryParam(curve, e, signature, Q) {
|
|
9074
|
+
for (let i = 0; i < 4; i++) {
|
|
9075
|
+
try {
|
|
9076
|
+
const Qprime = recoverPubKey(curve, e, signature, i);
|
|
9077
|
+
// 1.6.2 Verify Q = Q'
|
|
9078
|
+
if (Qprime.equals(Q)) {
|
|
9079
|
+
return i;
|
|
9080
|
+
}
|
|
9081
|
+
}
|
|
9082
|
+
catch (error) {
|
|
9083
|
+
// try next value
|
|
9084
|
+
}
|
|
9085
|
+
}
|
|
9086
|
+
throw new Error('Unable to find valid recovery factor');
|
|
9087
|
+
}
|
|
9088
|
+
|
|
8720
9089
|
const secp256k1 = libExports$1.getCurveByName('secp256k1');
|
|
8721
9090
|
class Signature {
|
|
8722
9091
|
constructor(r, s, i) {
|
|
@@ -8756,28 +9125,27 @@ class Signature {
|
|
|
8756
9125
|
throw new Error('private_key required');
|
|
8757
9126
|
}
|
|
8758
9127
|
const e = bigi.fromBuffer(buf_sha256);
|
|
8759
|
-
|
|
8760
|
-
|
|
8761
|
-
const d = privKey.d;
|
|
8762
|
-
let r, s;
|
|
9128
|
+
let ecsignature;
|
|
9129
|
+
let i = null;
|
|
8763
9130
|
let nonce = 0;
|
|
9131
|
+
// Match old-steem-js behavior: find canonical signature (lenR === 32 && lenS === 32)
|
|
8764
9132
|
while (true) {
|
|
8765
|
-
|
|
8766
|
-
const
|
|
8767
|
-
|
|
8768
|
-
|
|
8769
|
-
|
|
8770
|
-
|
|
8771
|
-
|
|
8772
|
-
|
|
8773
|
-
|
|
8774
|
-
|
|
8775
|
-
|
|
8776
|
-
|
|
8777
|
-
|
|
9133
|
+
ecsignature = sign$3(secp256k1, buf_sha256, privKey.d, nonce++);
|
|
9134
|
+
const der = ecsignature.toDER();
|
|
9135
|
+
const lenR = der[3];
|
|
9136
|
+
const lenS = der[5 + lenR];
|
|
9137
|
+
if (lenR === 32 && lenS === 32) {
|
|
9138
|
+
// Calculate recovery parameter to match old-steem-js
|
|
9139
|
+
i = calcPubKeyRecoveryParam(secp256k1, e, ecsignature, privKey.toPublic().Q);
|
|
9140
|
+
i += 4; // compressed
|
|
9141
|
+
i += 27; // compact
|
|
9142
|
+
break;
|
|
9143
|
+
}
|
|
9144
|
+
if (nonce % 10 === 0) {
|
|
9145
|
+
debug.warn("WARN: " + nonce + " attempts to find canonical signature");
|
|
9146
|
+
}
|
|
8778
9147
|
}
|
|
8779
|
-
|
|
8780
|
-
return new Signature(r, s, i);
|
|
9148
|
+
return new Signature(ecsignature.r, ecsignature.s, i);
|
|
8781
9149
|
}
|
|
8782
9150
|
static sign(string, private_key) {
|
|
8783
9151
|
return Signature.signBuffer(Buffer.from(string), private_key);
|
|
@@ -9949,7 +10317,18 @@ class HttpTransport extends BaseTransport {
|
|
|
9949
10317
|
timeout: timeoutMs,
|
|
9950
10318
|
})
|
|
9951
10319
|
.then((res) => res.json())
|
|
9952
|
-
.then((result) =>
|
|
10320
|
+
.then((result) => {
|
|
10321
|
+
// Check for JSON-RPC errors
|
|
10322
|
+
if (result.error) {
|
|
10323
|
+
const error = new Error(result.error.message || 'JSON-RPC error');
|
|
10324
|
+
error.code = result.error.code;
|
|
10325
|
+
error.data = result.error.data;
|
|
10326
|
+
callback(error, undefined, currentAttempt);
|
|
10327
|
+
}
|
|
10328
|
+
else {
|
|
10329
|
+
callback(null, result.result, currentAttempt);
|
|
10330
|
+
}
|
|
10331
|
+
}, (error) => {
|
|
9953
10332
|
if (operation.retry(error)) {
|
|
9954
10333
|
return;
|
|
9955
10334
|
}
|
|
@@ -9970,7 +10349,18 @@ class HttpTransport extends BaseTransport {
|
|
|
9970
10349
|
timeout: timeoutMs,
|
|
9971
10350
|
})
|
|
9972
10351
|
.then((res) => res.json())
|
|
9973
|
-
.then((result) =>
|
|
10352
|
+
.then((result) => {
|
|
10353
|
+
// Check for JSON-RPC errors
|
|
10354
|
+
if (result.error) {
|
|
10355
|
+
const error = new Error(result.error.message || 'JSON-RPC error');
|
|
10356
|
+
error.code = result.error.code;
|
|
10357
|
+
error.data = result.error.data;
|
|
10358
|
+
callback(error, undefined, 1);
|
|
10359
|
+
}
|
|
10360
|
+
else {
|
|
10361
|
+
callback(null, result.result, 1);
|
|
10362
|
+
}
|
|
10363
|
+
}, (error) => callback(error, undefined, 1));
|
|
9974
10364
|
}
|
|
9975
10365
|
}
|
|
9976
10366
|
}
|
|
@@ -21871,6 +22261,179 @@ if (typeof BigInt === "function") {
|
|
|
21871
22261
|
};
|
|
21872
22262
|
}
|
|
21873
22263
|
|
|
22264
|
+
/**
|
|
22265
|
+
* Serialize a transaction to binary format for Steem blockchain
|
|
22266
|
+
* This is a simplified implementation that handles the basic structure
|
|
22267
|
+
*/
|
|
22268
|
+
function serializeTransaction$1(trx) {
|
|
22269
|
+
const bb = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
|
|
22270
|
+
// Write ref_block_num (uint16)
|
|
22271
|
+
bb.writeUint16(trx.ref_block_num || 0);
|
|
22272
|
+
// Write ref_block_prefix (uint32)
|
|
22273
|
+
bb.writeUint32(trx.ref_block_prefix || 0);
|
|
22274
|
+
// Write expiration (time_point_sec - uint32 seconds since epoch)
|
|
22275
|
+
// Match old-steem-js behavior: ensure UTC time and precision to seconds
|
|
22276
|
+
let expiration;
|
|
22277
|
+
if (typeof trx.expiration === 'string') {
|
|
22278
|
+
// If string doesn't end with 'Z', append it to ensure UTC time
|
|
22279
|
+
let expirationStr = trx.expiration;
|
|
22280
|
+
if (!expirationStr.endsWith('Z')) {
|
|
22281
|
+
expirationStr = expirationStr + 'Z';
|
|
22282
|
+
}
|
|
22283
|
+
const date = new Date(expirationStr);
|
|
22284
|
+
expiration = Math.floor(date.getTime() / 1000);
|
|
22285
|
+
}
|
|
22286
|
+
else if (typeof trx.expiration === 'number') {
|
|
22287
|
+
expiration = trx.expiration;
|
|
22288
|
+
}
|
|
22289
|
+
else {
|
|
22290
|
+
expiration = 0;
|
|
22291
|
+
}
|
|
22292
|
+
bb.writeUint32(expiration);
|
|
22293
|
+
// Write operations array
|
|
22294
|
+
const operations = trx.operations || [];
|
|
22295
|
+
bb.writeVarint32(operations.length);
|
|
22296
|
+
for (const op of operations) {
|
|
22297
|
+
serializeOperation$1(bb, op);
|
|
22298
|
+
}
|
|
22299
|
+
// Write extensions (set of future_extensions, which is void/empty)
|
|
22300
|
+
bb.writeVarint32(0); // Empty set
|
|
22301
|
+
bb.flip();
|
|
22302
|
+
return Buffer.from(bb.toBuffer());
|
|
22303
|
+
}
|
|
22304
|
+
/**
|
|
22305
|
+
* Serialize an operation to binary format
|
|
22306
|
+
*/
|
|
22307
|
+
function serializeOperation$1(bb, op) {
|
|
22308
|
+
if (!Array.isArray(op) || op.length !== 2) {
|
|
22309
|
+
throw new Error('Operation must be an array of [operation_type, operation_data]');
|
|
22310
|
+
}
|
|
22311
|
+
const [opType, opData] = op;
|
|
22312
|
+
// Write operation type index (varint32)
|
|
22313
|
+
// For now, we'll use a simple mapping. In a full implementation,
|
|
22314
|
+
// this would use the static_variant index
|
|
22315
|
+
const opTypeIndex = getOperationTypeIndex(opType);
|
|
22316
|
+
bb.writeVarint32(opTypeIndex);
|
|
22317
|
+
// Serialize operation data based on type
|
|
22318
|
+
serializeOperationData(bb, opType, opData);
|
|
22319
|
+
}
|
|
22320
|
+
/**
|
|
22321
|
+
* Get operation type index based on Steem blockchain operation order
|
|
22322
|
+
* This matches the operation.st_operations array from the blockchain
|
|
22323
|
+
*/
|
|
22324
|
+
function getOperationTypeIndex(opType) {
|
|
22325
|
+
// Operation type indices based on Steem blockchain operation.st_operations
|
|
22326
|
+
const opMap = {
|
|
22327
|
+
'vote': 0,
|
|
22328
|
+
'comment': 1,
|
|
22329
|
+
'transfer': 2,
|
|
22330
|
+
'transfer_to_vesting': 3,
|
|
22331
|
+
'withdraw_vesting': 4,
|
|
22332
|
+
'limit_order_create': 5,
|
|
22333
|
+
'limit_order_cancel': 6,
|
|
22334
|
+
'feed_publish': 7,
|
|
22335
|
+
'convert': 8,
|
|
22336
|
+
'account_create': 9,
|
|
22337
|
+
'account_update': 10,
|
|
22338
|
+
'witness_update': 11,
|
|
22339
|
+
'account_witness_vote': 12,
|
|
22340
|
+
'account_witness_proxy': 13,
|
|
22341
|
+
'pow': 14,
|
|
22342
|
+
'custom': 15,
|
|
22343
|
+
'delete_comment': 17,
|
|
22344
|
+
'custom_json': 18,
|
|
22345
|
+
'comment_options': 19,
|
|
22346
|
+
};
|
|
22347
|
+
const index = opMap[opType];
|
|
22348
|
+
if (index === undefined) {
|
|
22349
|
+
throw new Error(`Unknown operation type: ${opType}. Please add it to the operation map.`);
|
|
22350
|
+
}
|
|
22351
|
+
return index;
|
|
22352
|
+
}
|
|
22353
|
+
/**
|
|
22354
|
+
* Serialize operation data based on operation type
|
|
22355
|
+
*/
|
|
22356
|
+
function serializeOperationData(bb, opType, opData) {
|
|
22357
|
+
switch (opType) {
|
|
22358
|
+
case 'comment':
|
|
22359
|
+
serializeComment(bb, opData);
|
|
22360
|
+
break;
|
|
22361
|
+
case 'vote':
|
|
22362
|
+
serializeVote(bb, opData);
|
|
22363
|
+
break;
|
|
22364
|
+
case 'transfer':
|
|
22365
|
+
serializeTransfer(bb, opData);
|
|
22366
|
+
break;
|
|
22367
|
+
default:
|
|
22368
|
+
// For other operations, try to serialize common fields
|
|
22369
|
+
// This is a fallback and may not work for all operations
|
|
22370
|
+
throw new Error(`Operation type ${opType} serialization not fully implemented`);
|
|
22371
|
+
}
|
|
22372
|
+
}
|
|
22373
|
+
/**
|
|
22374
|
+
* Serialize comment operation
|
|
22375
|
+
*/
|
|
22376
|
+
function serializeComment(bb, data) {
|
|
22377
|
+
writeString(bb, data.parent_author || '');
|
|
22378
|
+
writeString(bb, data.parent_permlink || '');
|
|
22379
|
+
writeString(bb, data.author || '');
|
|
22380
|
+
writeString(bb, data.permlink || '');
|
|
22381
|
+
writeString(bb, data.title || '');
|
|
22382
|
+
writeString(bb, data.body || '');
|
|
22383
|
+
writeString(bb, data.json_metadata || '{}');
|
|
22384
|
+
}
|
|
22385
|
+
/**
|
|
22386
|
+
* Serialize vote operation
|
|
22387
|
+
*/
|
|
22388
|
+
function serializeVote(bb, data) {
|
|
22389
|
+
writeString(bb, data.voter || '');
|
|
22390
|
+
writeString(bb, data.author || '');
|
|
22391
|
+
writeString(bb, data.permlink || '');
|
|
22392
|
+
bb.writeInt16(data.weight || 0);
|
|
22393
|
+
}
|
|
22394
|
+
/**
|
|
22395
|
+
* Serialize transfer operation (simplified - asset serialization is complex)
|
|
22396
|
+
*/
|
|
22397
|
+
function serializeTransfer(bb, data) {
|
|
22398
|
+
writeString(bb, data.from || '');
|
|
22399
|
+
writeString(bb, data.to || '');
|
|
22400
|
+
// Asset serialization is complex and requires parsing amount string
|
|
22401
|
+
// For now, this is a placeholder
|
|
22402
|
+
serializeAsset(bb, data.amount || '0.000 STEEM');
|
|
22403
|
+
writeString(bb, data.memo || '');
|
|
22404
|
+
}
|
|
22405
|
+
/**
|
|
22406
|
+
* Serialize asset (simplified - full implementation is complex)
|
|
22407
|
+
*/
|
|
22408
|
+
function serializeAsset(bb, amount) {
|
|
22409
|
+
// Parse amount string like "1.000 STEEM"
|
|
22410
|
+
const parts = amount.split(' ');
|
|
22411
|
+
const valueStr = parts[0] || '0.000';
|
|
22412
|
+
const symbol = parts[1] || 'STEEM';
|
|
22413
|
+
// Parse decimal value
|
|
22414
|
+
const [intPart, decPart = ''] = valueStr.split('.');
|
|
22415
|
+
const precision = decPart.length;
|
|
22416
|
+
const amountValue = parseInt(intPart + decPart.padEnd(precision, '0'), 10);
|
|
22417
|
+
// Write amount as int64
|
|
22418
|
+
const amountLong = Long.fromNumber(amountValue, false);
|
|
22419
|
+
bb.writeInt64(amountLong);
|
|
22420
|
+
// Write precision and symbol (uint8 + 7 bytes)
|
|
22421
|
+
bb.writeUint8(precision);
|
|
22422
|
+
const symbolBytes = Buffer.from(symbol, 'utf8');
|
|
22423
|
+
bb.append(symbolBytes);
|
|
22424
|
+
// Pad to 7 bytes
|
|
22425
|
+
for (let i = symbolBytes.length; i < 7; i++) {
|
|
22426
|
+
bb.writeUint8(0);
|
|
22427
|
+
}
|
|
22428
|
+
}
|
|
22429
|
+
/**
|
|
22430
|
+
* Write a string using ByteBuffer's writeVString method
|
|
22431
|
+
* This matches the old implementation exactly
|
|
22432
|
+
*/
|
|
22433
|
+
function writeString(bb, str) {
|
|
22434
|
+
bb.writeVString(str);
|
|
22435
|
+
}
|
|
22436
|
+
|
|
21874
22437
|
class Serializer {
|
|
21875
22438
|
static fromBuffer(buffer) {
|
|
21876
22439
|
const bb = ByteBuffer.fromBinary(buffer.toString('binary'), ByteBuffer.LITTLE_ENDIAN);
|
|
@@ -21933,7 +22496,8 @@ class Serializer {
|
|
|
21933
22496
|
}
|
|
21934
22497
|
const transaction = {
|
|
21935
22498
|
toBuffer(trx) {
|
|
21936
|
-
|
|
22499
|
+
// Use binary serialization for proper signature generation
|
|
22500
|
+
return serializeTransaction$1(trx);
|
|
21937
22501
|
}
|
|
21938
22502
|
};
|
|
21939
22503
|
const signed_transaction = {
|
|
@@ -21945,6 +22509,13 @@ const signed_transaction = {
|
|
|
21945
22509
|
}
|
|
21946
22510
|
};
|
|
21947
22511
|
|
|
22512
|
+
const serializer$1 = /*#__PURE__*/Object.freeze({
|
|
22513
|
+
__proto__: null,
|
|
22514
|
+
Serializer: Serializer,
|
|
22515
|
+
signed_transaction: signed_transaction,
|
|
22516
|
+
transaction: transaction
|
|
22517
|
+
});
|
|
22518
|
+
|
|
21948
22519
|
const Auth = {
|
|
21949
22520
|
verify(name, password, auths) {
|
|
21950
22521
|
let hasKey = false;
|
|
@@ -22026,13 +22597,15 @@ const Auth = {
|
|
|
22026
22597
|
}
|
|
22027
22598
|
const signatures = [];
|
|
22028
22599
|
if (trx.signatures) {
|
|
22029
|
-
signatures.push(...trx.signatures.map((sig) => Buffer.
|
|
22600
|
+
signatures.push(...trx.signatures.map((sig) => Buffer.isBuffer(sig) ? sig.toString('hex') : sig));
|
|
22030
22601
|
}
|
|
22031
22602
|
const cid = Buffer.from(getConfig().get('chain_id') || '', 'hex');
|
|
22032
22603
|
const buf = transaction.toBuffer(trx);
|
|
22033
22604
|
for (const key of keys) {
|
|
22034
22605
|
const sig = Signature.signBuffer(Buffer.concat([cid, buf]), key);
|
|
22035
|
-
|
|
22606
|
+
// Use toBuffer() to match old-steem-js behavior
|
|
22607
|
+
// The serializer will convert Buffer to hex string when needed
|
|
22608
|
+
signatures.push(sig.toBuffer().toString('hex'));
|
|
22036
22609
|
}
|
|
22037
22610
|
return signed_transaction.toObject(Object.assign(trx, { signatures }));
|
|
22038
22611
|
}
|
|
@@ -22369,6 +22942,21 @@ class Broadcast {
|
|
|
22369
22942
|
try {
|
|
22370
22943
|
// Prepare the transaction (fetch global props, block header, etc.)
|
|
22371
22944
|
const transaction = await broadcastMethods._prepareTransaction.call(this, tx);
|
|
22945
|
+
// Debug: Print transaction, digest, and hex before signing (if debug enabled)
|
|
22946
|
+
const { debug } = await Promise.resolve().then(function () { return debug$1; });
|
|
22947
|
+
if (debug.isEnabled('transaction')) {
|
|
22948
|
+
const { transaction: transactionSerializer } = await Promise.resolve().then(function () { return serializer$1; });
|
|
22949
|
+
const { getConfig } = await Promise.resolve().then(function () { return config$1; });
|
|
22950
|
+
const { createHash } = await import('crypto');
|
|
22951
|
+
const buf = transactionSerializer.toBuffer(transaction);
|
|
22952
|
+
const chainId = Buffer.from(getConfig().get('chain_id') || '', 'hex');
|
|
22953
|
+
const digest = createHash('sha256').update(Buffer.concat([chainId, buf])).digest();
|
|
22954
|
+
debug.transaction('\n=== Transaction Debug Info (before signing) ===');
|
|
22955
|
+
debug.transaction('Transaction:', JSON.stringify(transaction, null, 2));
|
|
22956
|
+
debug.transaction('Transaction.toHex():', buf.toString('hex'));
|
|
22957
|
+
debug.transaction('Digest (sha256(chain_id + transaction)):', digest.toString('hex'));
|
|
22958
|
+
debug.transaction('===============================================\n');
|
|
22959
|
+
}
|
|
22372
22960
|
// Ensure privKeys is always an array for signTransaction
|
|
22373
22961
|
const keysArray = Array.isArray(privKeys)
|
|
22374
22962
|
? privKeys
|
|
@@ -25729,7 +26317,7 @@ const doubleSha256 = (data) => {
|
|
|
25729
26317
|
return sha256(sha256(data));
|
|
25730
26318
|
};
|
|
25731
26319
|
const hmacSha256 = (key, data) => {
|
|
25732
|
-
return createHmac$
|
|
26320
|
+
return createHmac$2('sha256', key).update(data).digest();
|
|
25733
26321
|
};
|
|
25734
26322
|
/**
|
|
25735
26323
|
* Generate a cryptographically secure key pair using ECC secp256k1
|