@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.cjs
CHANGED
|
@@ -6085,6 +6085,98 @@ const setConfig = (newConfig) => {
|
|
|
6085
6085
|
// Alias for setConfig to match the API's setOptions
|
|
6086
6086
|
const setOptions$1 = setConfig;
|
|
6087
6087
|
|
|
6088
|
+
var config$1 = /*#__PURE__*/Object.freeze({
|
|
6089
|
+
__proto__: null,
|
|
6090
|
+
Config: Config,
|
|
6091
|
+
getConfig: getConfig,
|
|
6092
|
+
setConfig: setConfig,
|
|
6093
|
+
setOptions: setOptions$1
|
|
6094
|
+
});
|
|
6095
|
+
|
|
6096
|
+
/**
|
|
6097
|
+
* Debug utility for controlled debug output
|
|
6098
|
+
* Can be enabled via:
|
|
6099
|
+
* 1. Config: steem.config.set({ debug: true })
|
|
6100
|
+
* 2. Environment variable: DEBUG=steem-js or DEBUG=steem-js:*
|
|
6101
|
+
* 3. Specific debug flags: DEBUG=steem-js:transaction,steem-js:signature
|
|
6102
|
+
*/
|
|
6103
|
+
// Check if debug is enabled via environment variable
|
|
6104
|
+
const DEBUG_ENV = process.env.DEBUG || '';
|
|
6105
|
+
const DEBUG_ENABLED = DEBUG_ENV.includes('steem-js');
|
|
6106
|
+
// Parse debug flags from environment
|
|
6107
|
+
const DEBUG_FLAGS = DEBUG_ENV.split(',').map(f => f.trim());
|
|
6108
|
+
function isDebugEnabled(flag) {
|
|
6109
|
+
// Check config first
|
|
6110
|
+
const configDebug = getConfig().get('debug');
|
|
6111
|
+
if (configDebug === true) {
|
|
6112
|
+
return true;
|
|
6113
|
+
}
|
|
6114
|
+
if (configDebug === false) {
|
|
6115
|
+
return false;
|
|
6116
|
+
}
|
|
6117
|
+
// Check environment variable
|
|
6118
|
+
if (!DEBUG_ENABLED) {
|
|
6119
|
+
return false;
|
|
6120
|
+
}
|
|
6121
|
+
// If no flag specified, check for general steem-js debug
|
|
6122
|
+
if (!flag) {
|
|
6123
|
+
return DEBUG_ENV.includes('steem-js') && !DEBUG_ENV.includes('steem-js:');
|
|
6124
|
+
}
|
|
6125
|
+
// Check for specific flag
|
|
6126
|
+
const flagPattern = `steem-js:${flag}`;
|
|
6127
|
+
return DEBUG_FLAGS.some(f => f === flagPattern || f === 'steem-js:*');
|
|
6128
|
+
}
|
|
6129
|
+
const debug = {
|
|
6130
|
+
/**
|
|
6131
|
+
* Log debug information
|
|
6132
|
+
* @param flag - Optional debug flag (e.g., 'transaction', 'signature')
|
|
6133
|
+
* @param args - Arguments to log
|
|
6134
|
+
*/
|
|
6135
|
+
log(flag, ...args) {
|
|
6136
|
+
if (isDebugEnabled(flag)) {
|
|
6137
|
+
const prefix = flag ? `[steem-js:${flag}]` : '[steem-js]';
|
|
6138
|
+
console.log(prefix, ...args);
|
|
6139
|
+
}
|
|
6140
|
+
},
|
|
6141
|
+
/**
|
|
6142
|
+
* Log transaction debug info
|
|
6143
|
+
*/
|
|
6144
|
+
transaction(...args) {
|
|
6145
|
+
this.log('transaction', ...args);
|
|
6146
|
+
},
|
|
6147
|
+
/**
|
|
6148
|
+
* Log signature debug info
|
|
6149
|
+
*/
|
|
6150
|
+
signature(...args) {
|
|
6151
|
+
this.log('signature', ...args);
|
|
6152
|
+
},
|
|
6153
|
+
/**
|
|
6154
|
+
* Log warning (always shown, but can be controlled)
|
|
6155
|
+
*/
|
|
6156
|
+
warn(...args) {
|
|
6157
|
+
if (isDebugEnabled() || getConfig().get('debug_warnings') !== false) {
|
|
6158
|
+
console.warn('[steem-js]', ...args);
|
|
6159
|
+
}
|
|
6160
|
+
},
|
|
6161
|
+
/**
|
|
6162
|
+
* Log error (always shown)
|
|
6163
|
+
*/
|
|
6164
|
+
error(...args) {
|
|
6165
|
+
console.error('[steem-js]', ...args);
|
|
6166
|
+
},
|
|
6167
|
+
/**
|
|
6168
|
+
* Check if debug is enabled for a specific flag
|
|
6169
|
+
*/
|
|
6170
|
+
isEnabled(flag) {
|
|
6171
|
+
return isDebugEnabled(flag);
|
|
6172
|
+
}
|
|
6173
|
+
};
|
|
6174
|
+
|
|
6175
|
+
var debug$1 = /*#__PURE__*/Object.freeze({
|
|
6176
|
+
__proto__: null,
|
|
6177
|
+
debug: debug
|
|
6178
|
+
});
|
|
6179
|
+
|
|
6088
6180
|
const sleep = (ms) => {
|
|
6089
6181
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
6090
6182
|
};
|
|
@@ -6130,6 +6222,7 @@ var utils = /*#__PURE__*/Object.freeze({
|
|
|
6130
6222
|
__proto__: null,
|
|
6131
6223
|
camelCase: camelCase,
|
|
6132
6224
|
chunk: chunk,
|
|
6225
|
+
debug: debug,
|
|
6133
6226
|
flatten: flatten,
|
|
6134
6227
|
isValidAddress: isValidAddress,
|
|
6135
6228
|
isValidAmount: isValidAmount,
|
|
@@ -8310,17 +8403,18 @@ function requireCreateHash () {
|
|
|
8310
8403
|
var createHashExports = requireCreateHash();
|
|
8311
8404
|
var createHash = /*@__PURE__*/getDefaultExportFromCjs(createHashExports);
|
|
8312
8405
|
|
|
8313
|
-
var createHmac;
|
|
8406
|
+
var createHmac$1;
|
|
8314
8407
|
var hasRequiredCreateHmac;
|
|
8315
8408
|
|
|
8316
8409
|
function requireCreateHmac () {
|
|
8317
|
-
if (hasRequiredCreateHmac) return createHmac;
|
|
8410
|
+
if (hasRequiredCreateHmac) return createHmac$1;
|
|
8318
8411
|
hasRequiredCreateHmac = 1;
|
|
8319
|
-
createHmac = require$$3$1.createHmac;
|
|
8320
|
-
return createHmac;
|
|
8412
|
+
createHmac$1 = require$$3$1.createHmac;
|
|
8413
|
+
return createHmac$1;
|
|
8321
8414
|
}
|
|
8322
8415
|
|
|
8323
|
-
requireCreateHmac();
|
|
8416
|
+
var createHmacExports = requireCreateHmac();
|
|
8417
|
+
var createHmac = /*@__PURE__*/getDefaultExportFromCjs(createHmacExports);
|
|
8324
8418
|
|
|
8325
8419
|
/** @arg {string|Buffer} data
|
|
8326
8420
|
@arg {string} [digest = null] - 'hex', 'binary' or 'base64'
|
|
@@ -8342,6 +8436,9 @@ function sha512(data, encoding) {
|
|
|
8342
8436
|
}
|
|
8343
8437
|
return createHash('sha512').update(data).digest();
|
|
8344
8438
|
}
|
|
8439
|
+
function HmacSHA256(buffer, secret) {
|
|
8440
|
+
return createHmac('sha256', secret).update(buffer).digest();
|
|
8441
|
+
}
|
|
8345
8442
|
function ripemd160$1(data) {
|
|
8346
8443
|
return createHash('rmd160').update(data).digest();
|
|
8347
8444
|
}
|
|
@@ -8627,7 +8724,7 @@ class PrivateKey {
|
|
|
8627
8724
|
throw new Error("Expecting parameter to be a Buffer type");
|
|
8628
8725
|
}
|
|
8629
8726
|
if (32 !== buf.length) {
|
|
8630
|
-
|
|
8727
|
+
debug.warn(`WARN: Expecting 32 bytes, instead got ${buf.length}, stack trace:`, new Error().stack);
|
|
8631
8728
|
}
|
|
8632
8729
|
if (buf.length === 0) {
|
|
8633
8730
|
throw new Error("Empty buffer");
|
|
@@ -8746,6 +8843,278 @@ const toPublic = (data) => {
|
|
|
8746
8843
|
return data;
|
|
8747
8844
|
};
|
|
8748
8845
|
|
|
8846
|
+
function enforce(type, value) {
|
|
8847
|
+
switch (type) {
|
|
8848
|
+
case 'Array': {
|
|
8849
|
+
if (Array.isArray(value))
|
|
8850
|
+
return;
|
|
8851
|
+
break;
|
|
8852
|
+
}
|
|
8853
|
+
case 'Boolean': {
|
|
8854
|
+
if (typeof value === 'boolean')
|
|
8855
|
+
return;
|
|
8856
|
+
break;
|
|
8857
|
+
}
|
|
8858
|
+
case 'Buffer': {
|
|
8859
|
+
if (Buffer.isBuffer(value))
|
|
8860
|
+
return;
|
|
8861
|
+
break;
|
|
8862
|
+
}
|
|
8863
|
+
case 'Number': {
|
|
8864
|
+
if (typeof value === 'number')
|
|
8865
|
+
return;
|
|
8866
|
+
break;
|
|
8867
|
+
}
|
|
8868
|
+
case 'String': {
|
|
8869
|
+
if (typeof value === 'string')
|
|
8870
|
+
return;
|
|
8871
|
+
break;
|
|
8872
|
+
}
|
|
8873
|
+
default: {
|
|
8874
|
+
if (typeof type === 'function' && getName(value.constructor) === getName(type))
|
|
8875
|
+
return;
|
|
8876
|
+
}
|
|
8877
|
+
}
|
|
8878
|
+
throw new TypeError('Expected ' + (typeof type === 'function' ? getName(type) : type) + ', got ' + value);
|
|
8879
|
+
}
|
|
8880
|
+
function getName(fn) {
|
|
8881
|
+
const match = fn.toString().match(/function (.*?)\(/);
|
|
8882
|
+
return match ? match[1] : null;
|
|
8883
|
+
}
|
|
8884
|
+
|
|
8885
|
+
class ECSignature {
|
|
8886
|
+
constructor(r, s) {
|
|
8887
|
+
enforce(bigi, r);
|
|
8888
|
+
enforce(bigi, s);
|
|
8889
|
+
this.r = r;
|
|
8890
|
+
this.s = s;
|
|
8891
|
+
}
|
|
8892
|
+
static parseCompact(buffer) {
|
|
8893
|
+
if (buffer.length !== 65)
|
|
8894
|
+
throw new Error('Invalid signature length');
|
|
8895
|
+
let i = buffer.readUInt8(0) - 27;
|
|
8896
|
+
if ((i & 7) !== i)
|
|
8897
|
+
throw new Error('Invalid signature parameter');
|
|
8898
|
+
const compressed = !!(i & 4);
|
|
8899
|
+
i = i & 3;
|
|
8900
|
+
const r = bigi.fromBuffer(buffer.slice(1, 33));
|
|
8901
|
+
const s = bigi.fromBuffer(buffer.slice(33));
|
|
8902
|
+
return {
|
|
8903
|
+
compressed,
|
|
8904
|
+
i,
|
|
8905
|
+
signature: new ECSignature(r, s)
|
|
8906
|
+
};
|
|
8907
|
+
}
|
|
8908
|
+
static fromDER(buffer) {
|
|
8909
|
+
if (buffer.readUInt8(0) !== 0x30)
|
|
8910
|
+
throw new Error('Not a DER sequence');
|
|
8911
|
+
if (buffer.readUInt8(1) !== buffer.length - 2)
|
|
8912
|
+
throw new Error('Invalid sequence length');
|
|
8913
|
+
if (buffer.readUInt8(2) !== 0x02)
|
|
8914
|
+
throw new Error('Expected a DER integer');
|
|
8915
|
+
const rLen = buffer.readUInt8(3);
|
|
8916
|
+
if (rLen === 0)
|
|
8917
|
+
throw new Error('R length is zero');
|
|
8918
|
+
let offset = 4 + rLen;
|
|
8919
|
+
if (buffer.readUInt8(offset) !== 0x02)
|
|
8920
|
+
throw new Error('Expected a DER integer (2)');
|
|
8921
|
+
const sLen = buffer.readUInt8(offset + 1);
|
|
8922
|
+
if (sLen === 0)
|
|
8923
|
+
throw new Error('S length is zero');
|
|
8924
|
+
const rB = buffer.slice(4, offset);
|
|
8925
|
+
const sB = buffer.slice(offset + 2);
|
|
8926
|
+
offset += 2 + sLen;
|
|
8927
|
+
if (rLen > 1 && rB.readUInt8(0) === 0x00) {
|
|
8928
|
+
if (!(rB.readUInt8(1) & 0x80))
|
|
8929
|
+
throw new Error('R value excessively padded');
|
|
8930
|
+
}
|
|
8931
|
+
if (sLen > 1 && sB.readUInt8(0) === 0x00) {
|
|
8932
|
+
if (!(sB.readUInt8(1) & 0x80))
|
|
8933
|
+
throw new Error('S value excessively padded');
|
|
8934
|
+
}
|
|
8935
|
+
if (offset !== buffer.length)
|
|
8936
|
+
throw new Error('Invalid DER encoding');
|
|
8937
|
+
const r = bigi.fromBuffer(rB);
|
|
8938
|
+
const s = bigi.fromBuffer(sB);
|
|
8939
|
+
if (r.signum() < 0)
|
|
8940
|
+
throw new Error('R value is negative');
|
|
8941
|
+
if (s.signum() < 0)
|
|
8942
|
+
throw new Error('S value is negative');
|
|
8943
|
+
return new ECSignature(r, s);
|
|
8944
|
+
}
|
|
8945
|
+
static parseScriptSignature(buffer) {
|
|
8946
|
+
const hashType = buffer.readUInt8(buffer.length - 1);
|
|
8947
|
+
const hashTypeMod = hashType & -129;
|
|
8948
|
+
if (hashTypeMod <= 0x00 || hashTypeMod >= 0x04)
|
|
8949
|
+
throw new Error('Invalid hashType');
|
|
8950
|
+
return {
|
|
8951
|
+
signature: ECSignature.fromDER(buffer.slice(0, -1)),
|
|
8952
|
+
hashType
|
|
8953
|
+
};
|
|
8954
|
+
}
|
|
8955
|
+
toCompact(i, compressed) {
|
|
8956
|
+
if (compressed)
|
|
8957
|
+
i += 4;
|
|
8958
|
+
i += 27;
|
|
8959
|
+
const buffer = Buffer.alloc(65);
|
|
8960
|
+
buffer.writeUInt8(i, 0);
|
|
8961
|
+
this.r.toBuffer(32).copy(buffer, 1);
|
|
8962
|
+
this.s.toBuffer(32).copy(buffer, 33);
|
|
8963
|
+
return buffer;
|
|
8964
|
+
}
|
|
8965
|
+
toDER() {
|
|
8966
|
+
const rBa = this.r.toBuffer();
|
|
8967
|
+
const sBa = this.s.toBuffer();
|
|
8968
|
+
const sequence = [];
|
|
8969
|
+
// INTEGER
|
|
8970
|
+
sequence.push(0x02, rBa.length);
|
|
8971
|
+
Array.from(rBa).forEach(b => sequence.push(b));
|
|
8972
|
+
// INTEGER
|
|
8973
|
+
sequence.push(0x02, sBa.length);
|
|
8974
|
+
Array.from(sBa).forEach(b => sequence.push(b));
|
|
8975
|
+
// SEQUENCE
|
|
8976
|
+
sequence.unshift(0x30, sequence.length);
|
|
8977
|
+
return Buffer.from(sequence);
|
|
8978
|
+
}
|
|
8979
|
+
toScriptSignature(hashType) {
|
|
8980
|
+
const hashTypeBuffer = Buffer.alloc(1);
|
|
8981
|
+
hashTypeBuffer.writeUInt8(hashType, 0);
|
|
8982
|
+
return Buffer.concat([this.toDER(), hashTypeBuffer]);
|
|
8983
|
+
}
|
|
8984
|
+
}
|
|
8985
|
+
|
|
8986
|
+
// https://tools.ietf.org/html/rfc6979#section-3.2
|
|
8987
|
+
function deterministicGenerateK(curve, hash, d, checkSig, nonce) {
|
|
8988
|
+
enforce('Buffer', hash);
|
|
8989
|
+
enforce(bigi, d);
|
|
8990
|
+
if (nonce) {
|
|
8991
|
+
hash = sha256$1(Buffer.concat([hash, Buffer.alloc(nonce)]));
|
|
8992
|
+
}
|
|
8993
|
+
// sanity check
|
|
8994
|
+
assert.equal(hash.length, 32, 'Hash must be 256 bit');
|
|
8995
|
+
const x = d.toBuffer(32);
|
|
8996
|
+
let k = Buffer.alloc(32);
|
|
8997
|
+
let v = Buffer.alloc(32);
|
|
8998
|
+
// Step B
|
|
8999
|
+
v.fill(1);
|
|
9000
|
+
// Step C
|
|
9001
|
+
k.fill(0);
|
|
9002
|
+
// Step D
|
|
9003
|
+
k = HmacSHA256(Buffer.concat([v, Buffer.from([0]), x, hash]), k);
|
|
9004
|
+
// Step E
|
|
9005
|
+
v = HmacSHA256(v, k);
|
|
9006
|
+
// Step F
|
|
9007
|
+
k = HmacSHA256(Buffer.concat([v, Buffer.from([1]), x, hash]), k);
|
|
9008
|
+
// Step G
|
|
9009
|
+
v = HmacSHA256(v, k);
|
|
9010
|
+
// Step H1/H2a, ignored as tlen === qlen (256 bit)
|
|
9011
|
+
// Step H2b
|
|
9012
|
+
v = HmacSHA256(v, k);
|
|
9013
|
+
let T = bigi.fromBuffer(v);
|
|
9014
|
+
// Step H3, repeat until T is within the interval [1, n - 1] and passes the supplied check
|
|
9015
|
+
while ((T.signum() <= 0) || (T.compareTo(curve.n) >= 0) || !checkSig(T)) {
|
|
9016
|
+
k = HmacSHA256(Buffer.concat([v, Buffer.from([0])]), k);
|
|
9017
|
+
v = HmacSHA256(v, k);
|
|
9018
|
+
// Step H1/H2a, again, ignored as tlen === qlen (256 bit)
|
|
9019
|
+
// Step H2b again
|
|
9020
|
+
v = HmacSHA256(v, k);
|
|
9021
|
+
T = bigi.fromBuffer(v);
|
|
9022
|
+
}
|
|
9023
|
+
return T;
|
|
9024
|
+
}
|
|
9025
|
+
function sign$3(curve, hash, d, nonce) {
|
|
9026
|
+
const e = bigi.fromBuffer(hash);
|
|
9027
|
+
const n = curve.n;
|
|
9028
|
+
const G = curve.G;
|
|
9029
|
+
let r;
|
|
9030
|
+
let s;
|
|
9031
|
+
deterministicGenerateK(curve, hash, d, function (k) {
|
|
9032
|
+
// find canonically valid signature
|
|
9033
|
+
const Q = G.multiply(k);
|
|
9034
|
+
if (curve.isInfinity(Q))
|
|
9035
|
+
return false;
|
|
9036
|
+
const tempR = Q.affineX.mod(n);
|
|
9037
|
+
if (tempR.signum() === 0)
|
|
9038
|
+
return false;
|
|
9039
|
+
const tempS = k.modInverse(n).multiply(e.add(d.multiply(tempR))).mod(n);
|
|
9040
|
+
if (tempS.signum() === 0)
|
|
9041
|
+
return false;
|
|
9042
|
+
r = tempR;
|
|
9043
|
+
s = tempS;
|
|
9044
|
+
return true;
|
|
9045
|
+
}, nonce);
|
|
9046
|
+
if (!r || !s)
|
|
9047
|
+
throw new Error('Unable to find valid signature');
|
|
9048
|
+
const N_OVER_TWO = n.shiftRight(1);
|
|
9049
|
+
// enforce low S values, see bip62: 'low s values in signatures'
|
|
9050
|
+
const finalS = s.compareTo(N_OVER_TWO) > 0 ? n.subtract(s) : s;
|
|
9051
|
+
return new ECSignature(r, finalS);
|
|
9052
|
+
}
|
|
9053
|
+
/**
|
|
9054
|
+
* Recover a public key from a signature.
|
|
9055
|
+
*
|
|
9056
|
+
* See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public
|
|
9057
|
+
* Key Recovery Operation".
|
|
9058
|
+
*
|
|
9059
|
+
* http://www.secg.org/download/aid-780/sec1-v2.pdf
|
|
9060
|
+
*/
|
|
9061
|
+
function recoverPubKey(curve, e, signature, i) {
|
|
9062
|
+
assert.strictEqual(i & 3, i, 'Recovery param is more than two bits');
|
|
9063
|
+
const n = curve.n;
|
|
9064
|
+
const G = curve.G;
|
|
9065
|
+
const r = signature.r;
|
|
9066
|
+
const s = signature.s;
|
|
9067
|
+
assert(r.signum() > 0 && r.compareTo(n) < 0, 'Invalid r value');
|
|
9068
|
+
assert(s.signum() > 0 && s.compareTo(n) < 0, 'Invalid s value');
|
|
9069
|
+
// A set LSB signifies that the y-coordinate is odd
|
|
9070
|
+
const isYOdd = !!(i & 1);
|
|
9071
|
+
// The more significant bit specifies whether we should use the
|
|
9072
|
+
// first or second candidate key.
|
|
9073
|
+
const isSecondKey = i >> 1;
|
|
9074
|
+
// 1.1 Let x = r + jn
|
|
9075
|
+
const x = isSecondKey ? r.add(n) : r;
|
|
9076
|
+
const R = curve.pointFromX(isYOdd, x);
|
|
9077
|
+
// 1.4 Check that nR is at infinity
|
|
9078
|
+
const nR = R.multiply(n);
|
|
9079
|
+
assert(curve.isInfinity(nR), 'nR is not a valid curve point');
|
|
9080
|
+
// Compute -e from e
|
|
9081
|
+
const eNeg = e.negate().mod(n);
|
|
9082
|
+
// 1.6.1 Compute Q = r^-1 (sR - eG)
|
|
9083
|
+
// Q = r^-1 (sR + -eG)
|
|
9084
|
+
const rInv = r.modInverse(n);
|
|
9085
|
+
const sR = R.multiply(s);
|
|
9086
|
+
const eGNeg = G.multiply(eNeg);
|
|
9087
|
+
const Q = sR.add(eGNeg).multiply(rInv);
|
|
9088
|
+
curve.validate(Q);
|
|
9089
|
+
return Q;
|
|
9090
|
+
}
|
|
9091
|
+
/**
|
|
9092
|
+
* Calculate pubkey extraction parameter.
|
|
9093
|
+
*
|
|
9094
|
+
* When extracting a pubkey from a signature, we have to
|
|
9095
|
+
* distinguish four different cases. Rather than putting this
|
|
9096
|
+
* burden on the verifier, Bitcoin includes a 2-bit value with the
|
|
9097
|
+
* signature.
|
|
9098
|
+
*
|
|
9099
|
+
* This function simply tries all four cases and returns the value
|
|
9100
|
+
* that resulted in a successful pubkey recovery.
|
|
9101
|
+
*/
|
|
9102
|
+
function calcPubKeyRecoveryParam(curve, e, signature, Q) {
|
|
9103
|
+
for (let i = 0; i < 4; i++) {
|
|
9104
|
+
try {
|
|
9105
|
+
const Qprime = recoverPubKey(curve, e, signature, i);
|
|
9106
|
+
// 1.6.2 Verify Q = Q'
|
|
9107
|
+
if (Qprime.equals(Q)) {
|
|
9108
|
+
return i;
|
|
9109
|
+
}
|
|
9110
|
+
}
|
|
9111
|
+
catch (error) {
|
|
9112
|
+
// try next value
|
|
9113
|
+
}
|
|
9114
|
+
}
|
|
9115
|
+
throw new Error('Unable to find valid recovery factor');
|
|
9116
|
+
}
|
|
9117
|
+
|
|
8749
9118
|
const secp256k1 = libExports$1.getCurveByName('secp256k1');
|
|
8750
9119
|
class Signature {
|
|
8751
9120
|
constructor(r, s, i) {
|
|
@@ -8785,28 +9154,27 @@ class Signature {
|
|
|
8785
9154
|
throw new Error('private_key required');
|
|
8786
9155
|
}
|
|
8787
9156
|
const e = bigi.fromBuffer(buf_sha256);
|
|
8788
|
-
|
|
8789
|
-
|
|
8790
|
-
const d = privKey.d;
|
|
8791
|
-
let r, s;
|
|
9157
|
+
let ecsignature;
|
|
9158
|
+
let i = null;
|
|
8792
9159
|
let nonce = 0;
|
|
9160
|
+
// Match old-steem-js behavior: find canonical signature (lenR === 32 && lenS === 32)
|
|
8793
9161
|
while (true) {
|
|
8794
|
-
|
|
8795
|
-
const
|
|
8796
|
-
|
|
8797
|
-
|
|
8798
|
-
|
|
8799
|
-
|
|
8800
|
-
|
|
8801
|
-
|
|
8802
|
-
|
|
8803
|
-
|
|
8804
|
-
|
|
8805
|
-
|
|
8806
|
-
|
|
9162
|
+
ecsignature = sign$3(secp256k1, buf_sha256, privKey.d, nonce++);
|
|
9163
|
+
const der = ecsignature.toDER();
|
|
9164
|
+
const lenR = der[3];
|
|
9165
|
+
const lenS = der[5 + lenR];
|
|
9166
|
+
if (lenR === 32 && lenS === 32) {
|
|
9167
|
+
// Calculate recovery parameter to match old-steem-js
|
|
9168
|
+
i = calcPubKeyRecoveryParam(secp256k1, e, ecsignature, privKey.toPublic().Q);
|
|
9169
|
+
i += 4; // compressed
|
|
9170
|
+
i += 27; // compact
|
|
9171
|
+
break;
|
|
9172
|
+
}
|
|
9173
|
+
if (nonce % 10 === 0) {
|
|
9174
|
+
debug.warn("WARN: " + nonce + " attempts to find canonical signature");
|
|
9175
|
+
}
|
|
8807
9176
|
}
|
|
8808
|
-
|
|
8809
|
-
return new Signature(r, s, i);
|
|
9177
|
+
return new Signature(ecsignature.r, ecsignature.s, i);
|
|
8810
9178
|
}
|
|
8811
9179
|
static sign(string, private_key) {
|
|
8812
9180
|
return Signature.signBuffer(Buffer.from(string), private_key);
|
|
@@ -9978,7 +10346,18 @@ class HttpTransport extends BaseTransport {
|
|
|
9978
10346
|
timeout: timeoutMs,
|
|
9979
10347
|
})
|
|
9980
10348
|
.then((res) => res.json())
|
|
9981
|
-
.then((result) =>
|
|
10349
|
+
.then((result) => {
|
|
10350
|
+
// Check for JSON-RPC errors
|
|
10351
|
+
if (result.error) {
|
|
10352
|
+
const error = new Error(result.error.message || 'JSON-RPC error');
|
|
10353
|
+
error.code = result.error.code;
|
|
10354
|
+
error.data = result.error.data;
|
|
10355
|
+
callback(error, undefined, currentAttempt);
|
|
10356
|
+
}
|
|
10357
|
+
else {
|
|
10358
|
+
callback(null, result.result, currentAttempt);
|
|
10359
|
+
}
|
|
10360
|
+
}, (error) => {
|
|
9982
10361
|
if (operation.retry(error)) {
|
|
9983
10362
|
return;
|
|
9984
10363
|
}
|
|
@@ -9999,7 +10378,18 @@ class HttpTransport extends BaseTransport {
|
|
|
9999
10378
|
timeout: timeoutMs,
|
|
10000
10379
|
})
|
|
10001
10380
|
.then((res) => res.json())
|
|
10002
|
-
.then((result) =>
|
|
10381
|
+
.then((result) => {
|
|
10382
|
+
// Check for JSON-RPC errors
|
|
10383
|
+
if (result.error) {
|
|
10384
|
+
const error = new Error(result.error.message || 'JSON-RPC error');
|
|
10385
|
+
error.code = result.error.code;
|
|
10386
|
+
error.data = result.error.data;
|
|
10387
|
+
callback(error, undefined, 1);
|
|
10388
|
+
}
|
|
10389
|
+
else {
|
|
10390
|
+
callback(null, result.result, 1);
|
|
10391
|
+
}
|
|
10392
|
+
}, (error) => callback(error, undefined, 1));
|
|
10003
10393
|
}
|
|
10004
10394
|
}
|
|
10005
10395
|
}
|
|
@@ -21900,6 +22290,179 @@ if (typeof BigInt === "function") {
|
|
|
21900
22290
|
};
|
|
21901
22291
|
}
|
|
21902
22292
|
|
|
22293
|
+
/**
|
|
22294
|
+
* Serialize a transaction to binary format for Steem blockchain
|
|
22295
|
+
* This is a simplified implementation that handles the basic structure
|
|
22296
|
+
*/
|
|
22297
|
+
function serializeTransaction$1(trx) {
|
|
22298
|
+
const bb = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
|
|
22299
|
+
// Write ref_block_num (uint16)
|
|
22300
|
+
bb.writeUint16(trx.ref_block_num || 0);
|
|
22301
|
+
// Write ref_block_prefix (uint32)
|
|
22302
|
+
bb.writeUint32(trx.ref_block_prefix || 0);
|
|
22303
|
+
// Write expiration (time_point_sec - uint32 seconds since epoch)
|
|
22304
|
+
// Match old-steem-js behavior: ensure UTC time and precision to seconds
|
|
22305
|
+
let expiration;
|
|
22306
|
+
if (typeof trx.expiration === 'string') {
|
|
22307
|
+
// If string doesn't end with 'Z', append it to ensure UTC time
|
|
22308
|
+
let expirationStr = trx.expiration;
|
|
22309
|
+
if (!expirationStr.endsWith('Z')) {
|
|
22310
|
+
expirationStr = expirationStr + 'Z';
|
|
22311
|
+
}
|
|
22312
|
+
const date = new Date(expirationStr);
|
|
22313
|
+
expiration = Math.floor(date.getTime() / 1000);
|
|
22314
|
+
}
|
|
22315
|
+
else if (typeof trx.expiration === 'number') {
|
|
22316
|
+
expiration = trx.expiration;
|
|
22317
|
+
}
|
|
22318
|
+
else {
|
|
22319
|
+
expiration = 0;
|
|
22320
|
+
}
|
|
22321
|
+
bb.writeUint32(expiration);
|
|
22322
|
+
// Write operations array
|
|
22323
|
+
const operations = trx.operations || [];
|
|
22324
|
+
bb.writeVarint32(operations.length);
|
|
22325
|
+
for (const op of operations) {
|
|
22326
|
+
serializeOperation$1(bb, op);
|
|
22327
|
+
}
|
|
22328
|
+
// Write extensions (set of future_extensions, which is void/empty)
|
|
22329
|
+
bb.writeVarint32(0); // Empty set
|
|
22330
|
+
bb.flip();
|
|
22331
|
+
return Buffer.from(bb.toBuffer());
|
|
22332
|
+
}
|
|
22333
|
+
/**
|
|
22334
|
+
* Serialize an operation to binary format
|
|
22335
|
+
*/
|
|
22336
|
+
function serializeOperation$1(bb, op) {
|
|
22337
|
+
if (!Array.isArray(op) || op.length !== 2) {
|
|
22338
|
+
throw new Error('Operation must be an array of [operation_type, operation_data]');
|
|
22339
|
+
}
|
|
22340
|
+
const [opType, opData] = op;
|
|
22341
|
+
// Write operation type index (varint32)
|
|
22342
|
+
// For now, we'll use a simple mapping. In a full implementation,
|
|
22343
|
+
// this would use the static_variant index
|
|
22344
|
+
const opTypeIndex = getOperationTypeIndex(opType);
|
|
22345
|
+
bb.writeVarint32(opTypeIndex);
|
|
22346
|
+
// Serialize operation data based on type
|
|
22347
|
+
serializeOperationData(bb, opType, opData);
|
|
22348
|
+
}
|
|
22349
|
+
/**
|
|
22350
|
+
* Get operation type index based on Steem blockchain operation order
|
|
22351
|
+
* This matches the operation.st_operations array from the blockchain
|
|
22352
|
+
*/
|
|
22353
|
+
function getOperationTypeIndex(opType) {
|
|
22354
|
+
// Operation type indices based on Steem blockchain operation.st_operations
|
|
22355
|
+
const opMap = {
|
|
22356
|
+
'vote': 0,
|
|
22357
|
+
'comment': 1,
|
|
22358
|
+
'transfer': 2,
|
|
22359
|
+
'transfer_to_vesting': 3,
|
|
22360
|
+
'withdraw_vesting': 4,
|
|
22361
|
+
'limit_order_create': 5,
|
|
22362
|
+
'limit_order_cancel': 6,
|
|
22363
|
+
'feed_publish': 7,
|
|
22364
|
+
'convert': 8,
|
|
22365
|
+
'account_create': 9,
|
|
22366
|
+
'account_update': 10,
|
|
22367
|
+
'witness_update': 11,
|
|
22368
|
+
'account_witness_vote': 12,
|
|
22369
|
+
'account_witness_proxy': 13,
|
|
22370
|
+
'pow': 14,
|
|
22371
|
+
'custom': 15,
|
|
22372
|
+
'delete_comment': 17,
|
|
22373
|
+
'custom_json': 18,
|
|
22374
|
+
'comment_options': 19,
|
|
22375
|
+
};
|
|
22376
|
+
const index = opMap[opType];
|
|
22377
|
+
if (index === undefined) {
|
|
22378
|
+
throw new Error(`Unknown operation type: ${opType}. Please add it to the operation map.`);
|
|
22379
|
+
}
|
|
22380
|
+
return index;
|
|
22381
|
+
}
|
|
22382
|
+
/**
|
|
22383
|
+
* Serialize operation data based on operation type
|
|
22384
|
+
*/
|
|
22385
|
+
function serializeOperationData(bb, opType, opData) {
|
|
22386
|
+
switch (opType) {
|
|
22387
|
+
case 'comment':
|
|
22388
|
+
serializeComment(bb, opData);
|
|
22389
|
+
break;
|
|
22390
|
+
case 'vote':
|
|
22391
|
+
serializeVote(bb, opData);
|
|
22392
|
+
break;
|
|
22393
|
+
case 'transfer':
|
|
22394
|
+
serializeTransfer(bb, opData);
|
|
22395
|
+
break;
|
|
22396
|
+
default:
|
|
22397
|
+
// For other operations, try to serialize common fields
|
|
22398
|
+
// This is a fallback and may not work for all operations
|
|
22399
|
+
throw new Error(`Operation type ${opType} serialization not fully implemented`);
|
|
22400
|
+
}
|
|
22401
|
+
}
|
|
22402
|
+
/**
|
|
22403
|
+
* Serialize comment operation
|
|
22404
|
+
*/
|
|
22405
|
+
function serializeComment(bb, data) {
|
|
22406
|
+
writeString(bb, data.parent_author || '');
|
|
22407
|
+
writeString(bb, data.parent_permlink || '');
|
|
22408
|
+
writeString(bb, data.author || '');
|
|
22409
|
+
writeString(bb, data.permlink || '');
|
|
22410
|
+
writeString(bb, data.title || '');
|
|
22411
|
+
writeString(bb, data.body || '');
|
|
22412
|
+
writeString(bb, data.json_metadata || '{}');
|
|
22413
|
+
}
|
|
22414
|
+
/**
|
|
22415
|
+
* Serialize vote operation
|
|
22416
|
+
*/
|
|
22417
|
+
function serializeVote(bb, data) {
|
|
22418
|
+
writeString(bb, data.voter || '');
|
|
22419
|
+
writeString(bb, data.author || '');
|
|
22420
|
+
writeString(bb, data.permlink || '');
|
|
22421
|
+
bb.writeInt16(data.weight || 0);
|
|
22422
|
+
}
|
|
22423
|
+
/**
|
|
22424
|
+
* Serialize transfer operation (simplified - asset serialization is complex)
|
|
22425
|
+
*/
|
|
22426
|
+
function serializeTransfer(bb, data) {
|
|
22427
|
+
writeString(bb, data.from || '');
|
|
22428
|
+
writeString(bb, data.to || '');
|
|
22429
|
+
// Asset serialization is complex and requires parsing amount string
|
|
22430
|
+
// For now, this is a placeholder
|
|
22431
|
+
serializeAsset(bb, data.amount || '0.000 STEEM');
|
|
22432
|
+
writeString(bb, data.memo || '');
|
|
22433
|
+
}
|
|
22434
|
+
/**
|
|
22435
|
+
* Serialize asset (simplified - full implementation is complex)
|
|
22436
|
+
*/
|
|
22437
|
+
function serializeAsset(bb, amount) {
|
|
22438
|
+
// Parse amount string like "1.000 STEEM"
|
|
22439
|
+
const parts = amount.split(' ');
|
|
22440
|
+
const valueStr = parts[0] || '0.000';
|
|
22441
|
+
const symbol = parts[1] || 'STEEM';
|
|
22442
|
+
// Parse decimal value
|
|
22443
|
+
const [intPart, decPart = ''] = valueStr.split('.');
|
|
22444
|
+
const precision = decPart.length;
|
|
22445
|
+
const amountValue = parseInt(intPart + decPart.padEnd(precision, '0'), 10);
|
|
22446
|
+
// Write amount as int64
|
|
22447
|
+
const amountLong = Long.fromNumber(amountValue, false);
|
|
22448
|
+
bb.writeInt64(amountLong);
|
|
22449
|
+
// Write precision and symbol (uint8 + 7 bytes)
|
|
22450
|
+
bb.writeUint8(precision);
|
|
22451
|
+
const symbolBytes = Buffer.from(symbol, 'utf8');
|
|
22452
|
+
bb.append(symbolBytes);
|
|
22453
|
+
// Pad to 7 bytes
|
|
22454
|
+
for (let i = symbolBytes.length; i < 7; i++) {
|
|
22455
|
+
bb.writeUint8(0);
|
|
22456
|
+
}
|
|
22457
|
+
}
|
|
22458
|
+
/**
|
|
22459
|
+
* Write a string using ByteBuffer's writeVString method
|
|
22460
|
+
* This matches the old implementation exactly
|
|
22461
|
+
*/
|
|
22462
|
+
function writeString(bb, str) {
|
|
22463
|
+
bb.writeVString(str);
|
|
22464
|
+
}
|
|
22465
|
+
|
|
21903
22466
|
class Serializer {
|
|
21904
22467
|
static fromBuffer(buffer) {
|
|
21905
22468
|
const bb = ByteBuffer.fromBinary(buffer.toString('binary'), ByteBuffer.LITTLE_ENDIAN);
|
|
@@ -21962,7 +22525,8 @@ class Serializer {
|
|
|
21962
22525
|
}
|
|
21963
22526
|
const transaction = {
|
|
21964
22527
|
toBuffer(trx) {
|
|
21965
|
-
|
|
22528
|
+
// Use binary serialization for proper signature generation
|
|
22529
|
+
return serializeTransaction$1(trx);
|
|
21966
22530
|
}
|
|
21967
22531
|
};
|
|
21968
22532
|
const signed_transaction = {
|
|
@@ -21974,6 +22538,13 @@ const signed_transaction = {
|
|
|
21974
22538
|
}
|
|
21975
22539
|
};
|
|
21976
22540
|
|
|
22541
|
+
var serializer$1 = /*#__PURE__*/Object.freeze({
|
|
22542
|
+
__proto__: null,
|
|
22543
|
+
Serializer: Serializer,
|
|
22544
|
+
signed_transaction: signed_transaction,
|
|
22545
|
+
transaction: transaction
|
|
22546
|
+
});
|
|
22547
|
+
|
|
21977
22548
|
const Auth = {
|
|
21978
22549
|
verify(name, password, auths) {
|
|
21979
22550
|
let hasKey = false;
|
|
@@ -22055,13 +22626,15 @@ const Auth = {
|
|
|
22055
22626
|
}
|
|
22056
22627
|
const signatures = [];
|
|
22057
22628
|
if (trx.signatures) {
|
|
22058
|
-
signatures.push(...trx.signatures.map((sig) => Buffer.
|
|
22629
|
+
signatures.push(...trx.signatures.map((sig) => Buffer.isBuffer(sig) ? sig.toString('hex') : sig));
|
|
22059
22630
|
}
|
|
22060
22631
|
const cid = Buffer.from(getConfig().get('chain_id') || '', 'hex');
|
|
22061
22632
|
const buf = transaction.toBuffer(trx);
|
|
22062
22633
|
for (const key of keys) {
|
|
22063
22634
|
const sig = Signature.signBuffer(Buffer.concat([cid, buf]), key);
|
|
22064
|
-
|
|
22635
|
+
// Use toBuffer() to match old-steem-js behavior
|
|
22636
|
+
// The serializer will convert Buffer to hex string when needed
|
|
22637
|
+
signatures.push(sig.toBuffer().toString('hex'));
|
|
22065
22638
|
}
|
|
22066
22639
|
return signed_transaction.toObject(Object.assign(trx, { signatures }));
|
|
22067
22640
|
}
|
|
@@ -22398,6 +22971,21 @@ class Broadcast {
|
|
|
22398
22971
|
try {
|
|
22399
22972
|
// Prepare the transaction (fetch global props, block header, etc.)
|
|
22400
22973
|
const transaction = await broadcastMethods._prepareTransaction.call(this, tx);
|
|
22974
|
+
// Debug: Print transaction, digest, and hex before signing (if debug enabled)
|
|
22975
|
+
const { debug } = await Promise.resolve().then(function () { return debug$1; });
|
|
22976
|
+
if (debug.isEnabled('transaction')) {
|
|
22977
|
+
const { transaction: transactionSerializer } = await Promise.resolve().then(function () { return serializer$1; });
|
|
22978
|
+
const { getConfig } = await Promise.resolve().then(function () { return config$1; });
|
|
22979
|
+
const { createHash } = await import('crypto');
|
|
22980
|
+
const buf = transactionSerializer.toBuffer(transaction);
|
|
22981
|
+
const chainId = Buffer.from(getConfig().get('chain_id') || '', 'hex');
|
|
22982
|
+
const digest = createHash('sha256').update(Buffer.concat([chainId, buf])).digest();
|
|
22983
|
+
debug.transaction('\n=== Transaction Debug Info (before signing) ===');
|
|
22984
|
+
debug.transaction('Transaction:', JSON.stringify(transaction, null, 2));
|
|
22985
|
+
debug.transaction('Transaction.toHex():', buf.toString('hex'));
|
|
22986
|
+
debug.transaction('Digest (sha256(chain_id + transaction)):', digest.toString('hex'));
|
|
22987
|
+
debug.transaction('===============================================\n');
|
|
22988
|
+
}
|
|
22401
22989
|
// Ensure privKeys is always an array for signTransaction
|
|
22402
22990
|
const keysArray = Array.isArray(privKeys)
|
|
22403
22991
|
? privKeys
|