@clonegod/ttd-bsc-send-tx 2.0.2 → 2.0.3

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.
@@ -1,6 +1,7 @@
1
1
  export declare class _48ClubTrade {
2
2
  private rpcUrl;
3
3
  constructor();
4
+ sendPrivateTransaction(signedTx: string): Promise<string>;
4
5
  sendPrivateTransactionWith48SP(signedTx: string): Promise<string>;
5
6
  sendBundle(params: {
6
7
  txs: string[];
@@ -18,17 +18,28 @@ const sp_signature_1 = require("./sp_signature");
18
18
  const member_1 = require("./member");
19
19
  class _48ClubTrade {
20
20
  constructor() {
21
- this.rpcUrl = process.env._48CLUB_RPC_URL || 'https://puissant-bsc.48.club';
21
+ this.rpcUrl = process.env._48CLUB_RPC_URL || 'https://puissant-builder.48.club/';
22
+ }
23
+ sendPrivateTransaction(signedTx) {
24
+ return __awaiter(this, void 0, void 0, function* () {
25
+ const response = yield axios_1.default.post(this.rpcUrl, {
26
+ jsonrpc: "2.0", id: "1",
27
+ method: "eth_sendRawTransaction",
28
+ params: [signedTx]
29
+ });
30
+ if (response.data.error) {
31
+ throw new Error(`48club private tx: ${response.data.error.message}`);
32
+ }
33
+ return response.data.result;
34
+ });
22
35
  }
23
36
  sendPrivateTransactionWith48SP(signedTx) {
24
37
  return __awaiter(this, void 0, void 0, function* () {
25
- const spSign = yield this.get48SPSignature([signedTx]);
38
+ const spSignature = yield this.get48SPSignature([signedTx]);
26
39
  const response = yield axios_1.default.post(this.rpcUrl, {
27
- jsonrpc: "2.0", id: 1,
28
- method: "eth_sendPrivateTransaction",
29
- params: [{ tx: signedTx, preferences: { '48spSign': spSign } }]
30
- }, {
31
- headers: { 'Content-Type': 'application/json' }
40
+ jsonrpc: "2.0", id: "1",
41
+ method: "eth_sendPrivateTransactionWith48SP",
42
+ params: [signedTx, spSignature]
32
43
  });
33
44
  if (response.data.error) {
34
45
  throw new Error(`48club private tx: ${response.data.error.message}`);
@@ -39,17 +50,21 @@ class _48ClubTrade {
39
50
  sendBundle(params) {
40
51
  return __awaiter(this, void 0, void 0, function* () {
41
52
  const currentTimestamp = Math.floor(Date.now() / 1000);
42
- const spSign = yield this.get48SPSignature(params.txs);
53
+ const requestParams = {
54
+ txs: params.txs,
55
+ maxTimestamp: currentTimestamp + 2,
56
+ };
57
+ try {
58
+ const spSignature = yield this.get48SPSignature(params.txs);
59
+ requestParams['48spSign'] = spSignature;
60
+ }
61
+ catch (error) {
62
+ console.warn(`[48Club] 生成 48SP 签名失败,将发送不带签名的 Bundle: ${error.message}`);
63
+ }
43
64
  const response = yield axios_1.default.post(this.rpcUrl, {
44
- jsonrpc: "2.0", id: 1,
65
+ jsonrpc: "2.0", id: "1",
45
66
  method: "eth_sendBundle",
46
- params: [{
47
- txs: params.txs,
48
- maxTimestamp: currentTimestamp + 2,
49
- '48spSign': spSign
50
- }]
51
- }, {
52
- headers: { 'Content-Type': 'application/json' }
67
+ params: [requestParams]
53
68
  });
54
69
  if (response.data.error) {
55
70
  throw new Error(`48club bundle: ${response.data.error.message}`);
@@ -1,4 +1,6 @@
1
1
  export declare class SoulPointSignature {
2
2
  static generate48SPSignature(privateKey: string, txs: string[]): string;
3
+ private static signWithV5;
4
+ private static signWithV6;
3
5
  static verify48SPSignature(signature: string, txs: string[], expectedSignerAddress: string): boolean;
4
6
  }
@@ -4,30 +4,58 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.SoulPointSignature = void 0;
5
5
  const ethers_1 = require("ethers");
6
6
  const _ethers = ethers_1.ethers;
7
- const keccak256 = ((_a = _ethers.utils) === null || _a === void 0 ? void 0 : _a.keccak256) || _ethers.keccak256;
8
- const concat = ((_b = _ethers.utils) === null || _b === void 0 ? void 0 : _b.concat) || _ethers.concat;
9
- const recoverAddress = ((_c = _ethers.utils) === null || _c === void 0 ? void 0 : _c.recoverAddress) || _ethers.recoverAddress;
7
+ const keccak256Fn = ((_a = _ethers.utils) === null || _a === void 0 ? void 0 : _a.keccak256) || _ethers.keccak256;
8
+ const concatFn = ((_b = _ethers.utils) === null || _b === void 0 ? void 0 : _b.concat) || _ethers.concat;
9
+ const recoverAddressFn = ((_c = _ethers.utils) === null || _c === void 0 ? void 0 : _c.recoverAddress) || _ethers.recoverAddress;
10
10
  class SoulPointSignature {
11
11
  static generate48SPSignature(privateKey, txs) {
12
12
  const wallet = new ethers_1.ethers.Wallet(privateKey);
13
- const txHashes = txs.map(tx => tx.startsWith('0x') ? keccak256(tx) : tx);
14
- const concatenatedHashes = concat(txHashes);
15
- const messageHash = keccak256(concatenatedHashes);
16
- if (typeof wallet._signingKey === 'function') {
17
- const signature = wallet._signingKey().signDigest(messageHash);
18
- return signature.compact;
13
+ try {
14
+ return this.signWithV5(wallet, txs);
15
+ }
16
+ catch (_a) {
17
+ return this.signWithV6(wallet, txs);
18
+ }
19
+ }
20
+ static signWithV5(wallet, txs) {
21
+ const txHashes = txs.map(tx => tx.startsWith('0x') ? keccak256Fn(tx) : tx);
22
+ const concatenatedHashes = concatFn(txHashes);
23
+ const messageHash = keccak256Fn(concatenatedHashes);
24
+ const signature = wallet._signingKey().signDigest(messageHash);
25
+ const r = signature.r.slice(2).padStart(64, '0');
26
+ const s = signature.s.slice(2).padStart(64, '0');
27
+ const v = signature.recoveryParam.toString(16).padStart(2, '0');
28
+ return '0x' + r + s + v;
29
+ }
30
+ static signWithV6(wallet, txs) {
31
+ const txHashes = txs.map(tx => tx.startsWith('0x') ? keccak256Fn(tx) : tx);
32
+ const concatenatedHashes = concatFn(txHashes);
33
+ const messageHash = keccak256Fn(concatenatedHashes);
34
+ const signingKey = wallet.signingKey;
35
+ const signature = signingKey.sign(messageHash);
36
+ const r = signature.r.slice(2).padStart(64, '0');
37
+ const s = signature.s.slice(2).padStart(64, '0');
38
+ let recoveryId;
39
+ if (signature.recoveryParam !== undefined) {
40
+ recoveryId = Number(signature.recoveryParam);
41
+ }
42
+ else if (signature.v !== undefined) {
43
+ const v = Number(signature.v);
44
+ recoveryId = v >= 27 ? v - 27 : v;
19
45
  }
20
46
  else {
21
- const signature = wallet.signingKey.sign(messageHash);
22
- return signature.compactSerialized;
47
+ recoveryId = 0;
23
48
  }
49
+ recoveryId = recoveryId % 2;
50
+ const v = recoveryId.toString(16).padStart(2, '0');
51
+ return '0x' + r + s + v;
24
52
  }
25
53
  static verify48SPSignature(signature, txs, expectedSignerAddress) {
26
54
  try {
27
- const txHashes = txs.map(tx => tx.startsWith('0x') ? keccak256(tx) : tx);
28
- const concatenatedHashes = concat(txHashes);
29
- const messageHash = keccak256(concatenatedHashes);
30
- const recoveredAddr = recoverAddress(messageHash, signature);
55
+ const txHashes = txs.map(tx => tx.startsWith('0x') ? keccak256Fn(tx) : tx);
56
+ const concatenatedHashes = concatFn(txHashes);
57
+ const messageHash = keccak256Fn(concatenatedHashes);
58
+ const recoveredAddr = recoverAddressFn(messageHash, signature);
31
59
  return recoveredAddr.toLowerCase() === expectedSignerAddress.toLowerCase();
32
60
  }
33
61
  catch (_a) {
@@ -48,7 +48,7 @@ class TransactionSender {
48
48
  }),
49
49
  },
50
50
  {
51
- name: '48Club HTTP Private',
51
+ name: '48Club HTTP Private with 48SP',
52
52
  enable: process.env.SEND_TX_48CLUB_PRIVATE === 'true',
53
53
  is_bundle: false,
54
54
  send: () => __awaiter(this, void 0, void 0, function* () { return this._48Club.sendPrivateTransactionWith48SP(signedMainTx); }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clonegod/ttd-bsc-send-tx",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
4
4
  "description": "BSC 交易发送模块(HTTP直发 + WS bundle 转发)",
5
5
  "license": "UNLICENSED",
6
6
  "main": "dist/index.js",