@clonegod/ttd-bsc-send-tx 2.0.3 → 2.0.5
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/.env.example +40 -0
- package/dist/_48club/http.d.ts +1 -1
- package/dist/_48club/http.js +12 -4
- package/dist/_48club/member.js +2 -1
- package/dist/_48club/ws.js +4 -3
- package/dist/appconfig/EnvArgs.d.ts +24 -0
- package/dist/appconfig/EnvArgs.js +38 -0
- package/dist/appconfig/env_registry.d.ts +1 -0
- package/dist/appconfig/env_registry.js +8 -0
- package/dist/appconfig/index.d.ts +3 -0
- package/dist/appconfig/index.js +6 -0
- package/dist/blockrazor/index.d.ts +1 -2
- package/dist/blockrazor/index.js +12 -8
- package/dist/bloxroute/ws.js +5 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/rpc/index.js +2 -1
- package/dist/transaction_sender.d.ts +5 -1
- package/dist/transaction_sender.js +60 -48
- package/dist/ws_client.d.ts +3 -0
- package/dist/ws_client.js +30 -4
- package/dist/ws_server.js +38 -9
- package/package.json +3 -3
package/.env.example
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
APP_NAME=send-tx
|
|
2
|
+
|
|
3
|
+
CHAIN_ID=BSC
|
|
4
|
+
|
|
5
|
+
REDIS_HOST=127.0.0.1
|
|
6
|
+
REDIS_PORT=6379
|
|
7
|
+
|
|
8
|
+
LOG_LEVEL=INFO
|
|
9
|
+
LOG_DEPTH=4
|
|
10
|
+
|
|
11
|
+
# WS client(trade 进程连 send-tx server 用)
|
|
12
|
+
SEND_TX_WS_HOST=127.0.0.1
|
|
13
|
+
|
|
14
|
+
# WS server 开关
|
|
15
|
+
SEND_TX_48CLUB_WS=false
|
|
16
|
+
SEND_TX_BLOXROUTE_WS=false
|
|
17
|
+
|
|
18
|
+
# HTTP providers
|
|
19
|
+
SEND_TX_DEFAULT_RPC=false
|
|
20
|
+
SEND_TX_BLOCKRAZOR_PRIVATE=false
|
|
21
|
+
SEND_TX_BLOCKRAZOR_BUNDLE=false
|
|
22
|
+
SEND_TX_48CLUB_PRIVATE=false
|
|
23
|
+
SEND_TX_48CLUB_BUNDLE=false
|
|
24
|
+
SEND_TX_BLOX_BUNDLE_WS=false
|
|
25
|
+
SEND_TX_48CLUB_BUNDLE_WS=false
|
|
26
|
+
|
|
27
|
+
# Builder endpoints
|
|
28
|
+
BSC_RPC_ENDPOINT=
|
|
29
|
+
BLOXROUTE_WS_URL=
|
|
30
|
+
BLOX_AUTH_KEY=
|
|
31
|
+
_48CLUB_WS_URL=
|
|
32
|
+
_48CLUB_RPC_URL=
|
|
33
|
+
_48CLUB_SP_WALLET_ID=TTD-PAYMENT
|
|
34
|
+
BLOCKRAZOR_RPC_URL=
|
|
35
|
+
BLOCKRAZOR_AUTH_TOKEN=
|
|
36
|
+
|
|
37
|
+
# 间接依赖(通过 ttd-core 工具函数读取)
|
|
38
|
+
# load_wallet
|
|
39
|
+
WALLET_DIR=
|
|
40
|
+
ENCRYPTION_KEY=
|
package/dist/_48club/http.d.ts
CHANGED
package/dist/_48club/http.js
CHANGED
|
@@ -14,15 +14,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports._48ClubTrade = void 0;
|
|
16
16
|
const axios_1 = __importDefault(require("axios"));
|
|
17
|
+
const appconfig_1 = require("../appconfig");
|
|
18
|
+
const https_1 = __importDefault(require("https"));
|
|
17
19
|
const sp_signature_1 = require("./sp_signature");
|
|
18
20
|
const member_1 = require("./member");
|
|
19
21
|
class _48ClubTrade {
|
|
20
22
|
constructor() {
|
|
21
|
-
|
|
23
|
+
const rpcUrl = appconfig_1.envArgs._48club_rpc_url;
|
|
24
|
+
this.client = axios_1.default.create({
|
|
25
|
+
baseURL: rpcUrl,
|
|
26
|
+
headers: { 'Content-Type': 'application/json' },
|
|
27
|
+
httpsAgent: new https_1.default.Agent({ keepAlive: true, maxSockets: 10 }),
|
|
28
|
+
timeout: 5000,
|
|
29
|
+
});
|
|
22
30
|
}
|
|
23
31
|
sendPrivateTransaction(signedTx) {
|
|
24
32
|
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
-
const response = yield
|
|
33
|
+
const response = yield this.client.post('', {
|
|
26
34
|
jsonrpc: "2.0", id: "1",
|
|
27
35
|
method: "eth_sendRawTransaction",
|
|
28
36
|
params: [signedTx]
|
|
@@ -36,7 +44,7 @@ class _48ClubTrade {
|
|
|
36
44
|
sendPrivateTransactionWith48SP(signedTx) {
|
|
37
45
|
return __awaiter(this, void 0, void 0, function* () {
|
|
38
46
|
const spSignature = yield this.get48SPSignature([signedTx]);
|
|
39
|
-
const response = yield
|
|
47
|
+
const response = yield this.client.post('', {
|
|
40
48
|
jsonrpc: "2.0", id: "1",
|
|
41
49
|
method: "eth_sendPrivateTransactionWith48SP",
|
|
42
50
|
params: [signedTx, spSignature]
|
|
@@ -61,7 +69,7 @@ class _48ClubTrade {
|
|
|
61
69
|
catch (error) {
|
|
62
70
|
console.warn(`[48Club] 生成 48SP 签名失败,将发送不带签名的 Bundle: ${error.message}`);
|
|
63
71
|
}
|
|
64
|
-
const response = yield
|
|
72
|
+
const response = yield this.client.post('', {
|
|
65
73
|
jsonrpc: "2.0", id: "1",
|
|
66
74
|
method: "eth_sendBundle",
|
|
67
75
|
params: [requestParams]
|
package/dist/_48club/member.js
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.get_48club_sp_private_key = void 0;
|
|
4
4
|
const ttd_core_1 = require("@clonegod/ttd-core");
|
|
5
|
+
const appconfig_1 = require("../appconfig");
|
|
5
6
|
var _48club_sp_wallet_private_key = null;
|
|
6
7
|
const get_48club_sp_private_key = () => {
|
|
7
8
|
if (_48club_sp_wallet_private_key) {
|
|
8
9
|
return _48club_sp_wallet_private_key;
|
|
9
10
|
}
|
|
10
11
|
try {
|
|
11
|
-
const wallet = (0, ttd_core_1.load_wallet)(
|
|
12
|
+
const wallet = (0, ttd_core_1.load_wallet)(appconfig_1.envArgs._48club_sp_wallet_id, false);
|
|
12
13
|
console.log('Load 48club SP wallet success, wallet address:', wallet.public_key);
|
|
13
14
|
_48club_sp_wallet_private_key = wallet.private_key;
|
|
14
15
|
return _48club_sp_wallet_private_key;
|
package/dist/_48club/ws.js
CHANGED
|
@@ -11,10 +11,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports._48ClubWsSender = void 0;
|
|
13
13
|
const ttd_core_1 = require("@clonegod/ttd-core");
|
|
14
|
+
const appconfig_1 = require("../appconfig");
|
|
14
15
|
class _48ClubWsSender {
|
|
15
16
|
constructor() {
|
|
16
17
|
this.wsClient = null;
|
|
17
|
-
this.wsUrl =
|
|
18
|
+
this.wsUrl = appconfig_1.envArgs._48club_ws_url;
|
|
18
19
|
}
|
|
19
20
|
connect() {
|
|
20
21
|
var _a;
|
|
@@ -36,11 +37,11 @@ class _48ClubWsSender {
|
|
|
36
37
|
sendTransaction(request) {
|
|
37
38
|
return __awaiter(this, void 0, void 0, function* () {
|
|
38
39
|
if (!this.isConnected()) {
|
|
39
|
-
(0, ttd_core_1.
|
|
40
|
+
(0, ttd_core_1.log_error)('[48club-ws] not connected, dropping tx', new Error('48club not connected'));
|
|
40
41
|
return;
|
|
41
42
|
}
|
|
42
43
|
if (!request.tipTx) {
|
|
43
|
-
(0, ttd_core_1.
|
|
44
|
+
(0, ttd_core_1.log_error)('[48club-ws] tipTx required for bundle, dropping tx', new Error('tipTx required for bundle'));
|
|
44
45
|
return;
|
|
45
46
|
}
|
|
46
47
|
const currentTimestamp = Math.floor(Date.now() / 1000);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { EnvArgs as CoreEnvArgs } from '@clonegod/ttd-core/dist';
|
|
2
|
+
import './env_registry';
|
|
3
|
+
export declare class SendTxEnvArgs extends CoreEnvArgs {
|
|
4
|
+
rpc_endpoint: string;
|
|
5
|
+
wallet_dir: string;
|
|
6
|
+
encryption_key: string;
|
|
7
|
+
send_tx_ws_host: string;
|
|
8
|
+
send_tx_default_rpc: boolean;
|
|
9
|
+
send_tx_blockrazor_private: boolean;
|
|
10
|
+
send_tx_48club_private: boolean;
|
|
11
|
+
send_tx_blockrazor_bundle: boolean;
|
|
12
|
+
send_tx_48club_bundle: boolean;
|
|
13
|
+
send_tx_48club_bundle_ws: boolean;
|
|
14
|
+
send_tx_blox_bundle_ws: boolean;
|
|
15
|
+
bsc_rpc_endpoint: string;
|
|
16
|
+
bloxroute_ws_url: string;
|
|
17
|
+
blox_auth_key: string;
|
|
18
|
+
_48club_ws_url: string;
|
|
19
|
+
_48club_rpc_url: string;
|
|
20
|
+
_48club_sp_wallet_id: string;
|
|
21
|
+
blockrazor_rpc_url: string;
|
|
22
|
+
blockrazor_auth_token: string;
|
|
23
|
+
constructor();
|
|
24
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SendTxEnvArgs = void 0;
|
|
4
|
+
const dist_1 = require("@clonegod/ttd-core/dist");
|
|
5
|
+
require("./env_registry");
|
|
6
|
+
class SendTxEnvArgs extends dist_1.EnvArgs {
|
|
7
|
+
constructor() {
|
|
8
|
+
var _a, _b;
|
|
9
|
+
super();
|
|
10
|
+
const cfg = this._cfg;
|
|
11
|
+
this.app_name = (cfg.app_name || '').toLowerCase();
|
|
12
|
+
this.chain_id = (cfg.chain_id || '').toUpperCase();
|
|
13
|
+
this.server_id = (_a = cfg.server_id) !== null && _a !== void 0 ? _a : '';
|
|
14
|
+
this.redis_host = cfg.redis_host;
|
|
15
|
+
this.redis_port = String(cfg.redis_port);
|
|
16
|
+
this.rpc_endpoint = cfg.rpc_endpoint;
|
|
17
|
+
this.wallet_dir = cfg.wallet_dir;
|
|
18
|
+
this.encryption_key = (_b = cfg.encryption_key) !== null && _b !== void 0 ? _b : '';
|
|
19
|
+
this.send_tx_ws_host = cfg.send_tx_ws_host;
|
|
20
|
+
this.send_tx_default_rpc = cfg.send_tx_default_rpc;
|
|
21
|
+
this.send_tx_blockrazor_private = cfg.send_tx_blockrazor_private;
|
|
22
|
+
this.send_tx_48club_private = cfg.send_tx_48club_private;
|
|
23
|
+
this.send_tx_blockrazor_bundle = cfg.send_tx_blockrazor_bundle;
|
|
24
|
+
this.send_tx_48club_bundle = cfg.send_tx_48club_bundle;
|
|
25
|
+
this.send_tx_48club_bundle_ws = cfg.send_tx_48club_bundle_ws;
|
|
26
|
+
this.send_tx_blox_bundle_ws = cfg.send_tx_blox_bundle_ws;
|
|
27
|
+
this.bsc_rpc_endpoint = cfg.bsc_rpc_endpoint;
|
|
28
|
+
this.bloxroute_ws_url = cfg.bloxroute_ws_url;
|
|
29
|
+
this.blox_auth_key = cfg.blox_auth_key;
|
|
30
|
+
this._48club_ws_url = cfg._48club_ws_url;
|
|
31
|
+
this._48club_rpc_url = cfg._48club_rpc_url;
|
|
32
|
+
this._48club_sp_wallet_id = cfg._48club_sp_wallet_id;
|
|
33
|
+
this.blockrazor_rpc_url = cfg.blockrazor_rpc_url;
|
|
34
|
+
this.blockrazor_auth_token = cfg.blockrazor_auth_token;
|
|
35
|
+
(0, dist_1.printEnvConfig)('send-tx', this);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.SendTxEnvArgs = SendTxEnvArgs;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const ttd_core_1 = require("@clonegod/ttd-core");
|
|
4
|
+
(0, ttd_core_1.registerEnvVars)({
|
|
5
|
+
bloxroute_ws_url: { env: 'BLOXROUTE_WS_URL', type: 'string', default: 'wss://api.blxrbdn.com/ws', desc: 'BloxRoute WS URL(send-tx 上游)' },
|
|
6
|
+
blox_auth_key: { env: 'BLOX_AUTH_KEY', type: 'string', default: '', sensitive: true, desc: 'BloxRoute 认证 key(send-tx 上游)' },
|
|
7
|
+
_48club_ws_url: { env: '_48CLUB_WS_URL', type: 'string', default: 'wss://puissant-builder.48.club/', desc: '48Club WS URL(send-tx 上游)' },
|
|
8
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.envArgs = exports.SendTxEnvArgs = void 0;
|
|
4
|
+
const EnvArgs_1 = require("./EnvArgs");
|
|
5
|
+
Object.defineProperty(exports, "SendTxEnvArgs", { enumerable: true, get: function () { return EnvArgs_1.SendTxEnvArgs; } });
|
|
6
|
+
exports.envArgs = new EnvArgs_1.SendTxEnvArgs();
|
package/dist/blockrazor/index.js
CHANGED
|
@@ -14,21 +14,27 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.BlockRazorTrade = void 0;
|
|
16
16
|
const ttd_core_1 = require("@clonegod/ttd-core");
|
|
17
|
+
const appconfig_1 = require("../appconfig");
|
|
17
18
|
const axios_1 = __importDefault(require("axios"));
|
|
19
|
+
const https_1 = __importDefault(require("https"));
|
|
18
20
|
class BlockRazorTrade {
|
|
19
21
|
constructor() {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
const rpcUrl = appconfig_1.envArgs.blockrazor_rpc_url;
|
|
23
|
+
const authToken = appconfig_1.envArgs.blockrazor_auth_token;
|
|
24
|
+
this.client = axios_1.default.create({
|
|
25
|
+
baseURL: rpcUrl,
|
|
26
|
+
headers: { 'Content-Type': 'application/json', 'Authorization': authToken },
|
|
27
|
+
httpsAgent: new https_1.default.Agent({ keepAlive: true, maxSockets: 10 }),
|
|
28
|
+
timeout: 5000,
|
|
29
|
+
});
|
|
22
30
|
}
|
|
23
31
|
sendPrivateTransaction(signedTx) {
|
|
24
32
|
return __awaiter(this, void 0, void 0, function* () {
|
|
25
33
|
try {
|
|
26
|
-
const response = yield
|
|
34
|
+
const response = yield this.client.post('', {
|
|
27
35
|
jsonrpc: "2.0", id: "1",
|
|
28
36
|
method: "eth_sendPrivateTransaction",
|
|
29
37
|
params: [signedTx]
|
|
30
|
-
}, {
|
|
31
|
-
headers: { 'Content-Type': 'application/json', 'Authorization': this.authToken }
|
|
32
38
|
});
|
|
33
39
|
if (response.data.error) {
|
|
34
40
|
throw new Error(`${response.data.error.code} - ${response.data.error.message}`);
|
|
@@ -45,12 +51,10 @@ class BlockRazorTrade {
|
|
|
45
51
|
return __awaiter(this, void 0, void 0, function* () {
|
|
46
52
|
try {
|
|
47
53
|
const currentTimestamp = Math.floor(Date.now() / 1000);
|
|
48
|
-
const response = yield
|
|
54
|
+
const response = yield this.client.post('', {
|
|
49
55
|
jsonrpc: "2.0", id: "1",
|
|
50
56
|
method: "eth_sendBundle",
|
|
51
57
|
params: [{ txs: transactions, maxTimestamp: currentTimestamp + 5 }]
|
|
52
|
-
}, {
|
|
53
|
-
headers: { 'Content-Type': 'application/json', 'Authorization': this.authToken }
|
|
54
58
|
});
|
|
55
59
|
if (response.data.error) {
|
|
56
60
|
throw new Error(`Bundle: ${response.data.error.message}`);
|
package/dist/bloxroute/ws.js
CHANGED
|
@@ -11,11 +11,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.BloXRouteWsSender = void 0;
|
|
13
13
|
const ttd_core_1 = require("@clonegod/ttd-core");
|
|
14
|
+
const appconfig_1 = require("../appconfig");
|
|
14
15
|
class BloXRouteWsSender {
|
|
15
16
|
constructor() {
|
|
16
17
|
this.wsClient = null;
|
|
17
|
-
this.wsUrl =
|
|
18
|
-
this.authToken =
|
|
18
|
+
this.wsUrl = appconfig_1.envArgs.bloxroute_ws_url;
|
|
19
|
+
this.authToken = appconfig_1.envArgs.blox_auth_key;
|
|
19
20
|
}
|
|
20
21
|
connect() {
|
|
21
22
|
var _a;
|
|
@@ -40,11 +41,11 @@ class BloXRouteWsSender {
|
|
|
40
41
|
sendTransaction(request) {
|
|
41
42
|
return __awaiter(this, void 0, void 0, function* () {
|
|
42
43
|
if (!this.isConnected()) {
|
|
43
|
-
(0, ttd_core_1.
|
|
44
|
+
(0, ttd_core_1.log_error)('[bloxroute-ws] not connected, dropping tx', new Error('bloxroute not connected'));
|
|
44
45
|
return;
|
|
45
46
|
}
|
|
46
47
|
if (!request.tipTx) {
|
|
47
|
-
(0, ttd_core_1.
|
|
48
|
+
(0, ttd_core_1.log_error)('[bloxroute-ws] tipTx required for bundle, dropping tx', new Error('tipTx required for bundle'));
|
|
48
49
|
return;
|
|
49
50
|
}
|
|
50
51
|
const targetBlockNumber = request.blockNumber + 4;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -5,3 +5,4 @@ var transaction_sender_1 = require("./transaction_sender");
|
|
|
5
5
|
Object.defineProperty(exports, "TransactionSender", { enumerable: true, get: function () { return transaction_sender_1.TransactionSender; } });
|
|
6
6
|
var constants_1 = require("./constants");
|
|
7
7
|
Object.defineProperty(exports, "BSC_EOA_ADDRESS", { enumerable: true, get: function () { return constants_1.BSC_EOA_ADDRESS; } });
|
|
8
|
+
require("./config");
|
package/dist/rpc/index.js
CHANGED
|
@@ -11,9 +11,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.BscMainnetRpc = void 0;
|
|
13
13
|
const ttd_core_1 = require("@clonegod/ttd-core");
|
|
14
|
+
const appconfig_1 = require("../appconfig");
|
|
14
15
|
class BscMainnetRpc {
|
|
15
16
|
constructor(rpc_endpoint) {
|
|
16
|
-
this.url = rpc_endpoint ||
|
|
17
|
+
this.url = rpc_endpoint || appconfig_1.envArgs.bsc_rpc_endpoint;
|
|
17
18
|
this.headers = new Headers();
|
|
18
19
|
this.headers.append("Content-Type", "application/json");
|
|
19
20
|
}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { AppConfig } from '@clonegod/ttd-core';
|
|
2
|
+
interface TraceWriter {
|
|
3
|
+
mark(name: string): void;
|
|
4
|
+
}
|
|
2
5
|
export declare class TransactionSender {
|
|
3
6
|
private rpc;
|
|
4
7
|
private blockRazor;
|
|
5
8
|
private _48Club;
|
|
6
9
|
private sendBundleProxy;
|
|
7
10
|
constructor(appConfig: AppConfig);
|
|
8
|
-
sendTransaction(signedMainTx: string,
|
|
11
|
+
sendTransaction(signedMainTx: string, tipTxMap: Map<string, string>, order_trace_id: string, pair?: string, only_bundle?: boolean, trace?: TraceWriter): Promise<string[]>;
|
|
9
12
|
}
|
|
13
|
+
export {};
|
|
@@ -11,9 +11,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.TransactionSender = void 0;
|
|
13
13
|
const ttd_core_1 = require("@clonegod/ttd-core");
|
|
14
|
+
const appconfig_1 = require("./appconfig");
|
|
14
15
|
const rpc_1 = require("./rpc");
|
|
15
16
|
const blockrazor_1 = require("./blockrazor");
|
|
16
17
|
const _48club_1 = require("./_48club");
|
|
18
|
+
const sp_signature_1 = require("./_48club/sp_signature");
|
|
19
|
+
const member_1 = require("./_48club/member");
|
|
17
20
|
const ws_client_1 = require("./ws_client");
|
|
18
21
|
const constants_1 = require("./constants");
|
|
19
22
|
class TransactionSender {
|
|
@@ -23,93 +26,102 @@ class TransactionSender {
|
|
|
23
26
|
this._48Club = new _48club_1._48ClubTrade();
|
|
24
27
|
this.sendBundleProxy = new ws_client_1.BscSendTxProxy();
|
|
25
28
|
}
|
|
26
|
-
sendTransaction(signedMainTx_1,
|
|
27
|
-
return __awaiter(this, arguments, void 0, function* (signedMainTx,
|
|
28
|
-
const
|
|
29
|
+
sendTransaction(signedMainTx_1, tipTxMap_1, order_trace_id_1) {
|
|
30
|
+
return __awaiter(this, arguments, void 0, function* (signedMainTx, tipTxMap, order_trace_id, pair = '', only_bundle = false, trace) {
|
|
31
|
+
const results = [];
|
|
32
|
+
const errors = [];
|
|
33
|
+
if (appconfig_1.envArgs.send_tx_blox_bundle_ws) {
|
|
34
|
+
try {
|
|
35
|
+
const tipTx = tipTxMap.get(constants_1.BSC_EOA_ADDRESS.BLXR);
|
|
36
|
+
this.sendBundleProxy.sendTransaction('bloxroute', pair, signedMainTx, tipTx);
|
|
37
|
+
results.push('sent to bloxroute ws');
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
errors.push(`bloxroute_ws: ${error.message}`);
|
|
41
|
+
(0, ttd_core_1.log_info)(`Transaction send failed`, { provider: 'bloxroute_ws', order_trace_id, error: error.message });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (appconfig_1.envArgs.send_tx_48club_bundle_ws) {
|
|
45
|
+
try {
|
|
46
|
+
const tipTx = tipTxMap.get(constants_1.BSC_EOA_ADDRESS._48CLUB);
|
|
47
|
+
let spSignature;
|
|
48
|
+
try {
|
|
49
|
+
const privateKey = (0, member_1.get_48club_sp_private_key)();
|
|
50
|
+
if (privateKey) {
|
|
51
|
+
spSignature = sp_signature_1.SoulPointSignature.generate48SPSignature(privateKey, [signedMainTx, tipTx]);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (_a) { }
|
|
55
|
+
this.sendBundleProxy.sendTransaction('48club', pair, signedMainTx, tipTx, spSignature);
|
|
56
|
+
results.push('sent to 48club ws');
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
errors.push(`48club_ws: ${error.message}`);
|
|
60
|
+
(0, ttd_core_1.log_info)(`Transaction send failed`, { provider: '48club_ws', order_trace_id, error: error.message });
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
trace === null || trace === void 0 ? void 0 : trace.mark('ws_sent');
|
|
64
|
+
const httpProviders = [
|
|
29
65
|
{
|
|
30
|
-
name: '
|
|
31
|
-
enable:
|
|
66
|
+
name: 'default_rpc',
|
|
67
|
+
enable: appconfig_1.envArgs.send_tx_default_rpc,
|
|
32
68
|
is_bundle: false,
|
|
33
69
|
send: () => __awaiter(this, void 0, void 0, function* () { return this.rpc.eth_sendRawTransaction(signedMainTx); }),
|
|
34
70
|
},
|
|
35
71
|
{
|
|
36
|
-
name: '
|
|
37
|
-
enable:
|
|
72
|
+
name: 'blockrazor_private',
|
|
73
|
+
enable: appconfig_1.envArgs.send_tx_blockrazor_private,
|
|
38
74
|
is_bundle: false,
|
|
39
75
|
send: () => __awaiter(this, void 0, void 0, function* () { return this.blockRazor.sendPrivateTransaction(signedMainTx); }),
|
|
40
76
|
},
|
|
41
77
|
{
|
|
42
|
-
name: '
|
|
43
|
-
enable:
|
|
78
|
+
name: 'blockrazor_bundle',
|
|
79
|
+
enable: appconfig_1.envArgs.send_tx_blockrazor_bundle,
|
|
44
80
|
is_bundle: true,
|
|
45
81
|
send: () => __awaiter(this, void 0, void 0, function* () {
|
|
46
|
-
const
|
|
47
|
-
return this.blockRazor.sendBundle(
|
|
82
|
+
const tipTx = tipTxMap.get(constants_1.BSC_EOA_ADDRESS.BLOCKRAZOR);
|
|
83
|
+
return this.blockRazor.sendBundle([signedMainTx, tipTx]);
|
|
48
84
|
}),
|
|
49
85
|
},
|
|
50
86
|
{
|
|
51
|
-
name: '
|
|
52
|
-
enable:
|
|
87
|
+
name: '48club_private',
|
|
88
|
+
enable: appconfig_1.envArgs.send_tx_48club_private,
|
|
53
89
|
is_bundle: false,
|
|
54
90
|
send: () => __awaiter(this, void 0, void 0, function* () { return this._48Club.sendPrivateTransactionWith48SP(signedMainTx); }),
|
|
55
91
|
},
|
|
56
92
|
{
|
|
57
|
-
name: '
|
|
58
|
-
enable:
|
|
93
|
+
name: '48club_bundle',
|
|
94
|
+
enable: appconfig_1.envArgs.send_tx_48club_bundle,
|
|
59
95
|
is_bundle: true,
|
|
60
96
|
send: () => __awaiter(this, void 0, void 0, function* () {
|
|
61
|
-
const
|
|
62
|
-
return this._48Club.sendBundle({ txs:
|
|
63
|
-
}),
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
name: '48Club WS Bundle',
|
|
67
|
-
enable: process.env.SEND_TX_48CLUB_BUNDLE_WS === 'true',
|
|
68
|
-
is_bundle: true,
|
|
69
|
-
send: () => __awaiter(this, void 0, void 0, function* () {
|
|
70
|
-
const tipTx = yield eoa_tip_transaction(constants_1.BSC_EOA_ADDRESS._48CLUB);
|
|
71
|
-
const spSignature = yield this._48Club.get48SPSignature([signedMainTx, tipTx]);
|
|
72
|
-
this.sendBundleProxy.sendTransaction('48club', pair, signedMainTx, tipTx, spSignature);
|
|
73
|
-
return 'sent to 48club ws';
|
|
74
|
-
}),
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
name: 'BloxRoute WS Bundle',
|
|
78
|
-
enable: process.env.SEND_TX_BLOX_BUNDLE_WS === 'true',
|
|
79
|
-
is_bundle: true,
|
|
80
|
-
send: () => __awaiter(this, void 0, void 0, function* () {
|
|
81
|
-
const tipTx = yield eoa_tip_transaction(constants_1.BSC_EOA_ADDRESS.BLXR);
|
|
82
|
-
this.sendBundleProxy.sendTransaction('bloxroute', pair, signedMainTx, tipTx);
|
|
83
|
-
return 'sent to bloxroute ws';
|
|
97
|
+
const tipTx = tipTxMap.get(constants_1.BSC_EOA_ADDRESS._48CLUB);
|
|
98
|
+
return this._48Club.sendBundle({ txs: [signedMainTx, tipTx] });
|
|
84
99
|
}),
|
|
85
100
|
},
|
|
86
101
|
];
|
|
87
|
-
|
|
88
|
-
const errors = [];
|
|
89
|
-
yield Promise.all(rpcProviders
|
|
102
|
+
yield Promise.all(httpProviders
|
|
90
103
|
.filter(p => p.enable)
|
|
91
104
|
.filter(p => only_bundle ? p.is_bundle : true)
|
|
92
105
|
.map((provider) => __awaiter(this, void 0, void 0, function* () {
|
|
93
106
|
try {
|
|
94
107
|
const txHash = yield provider.send();
|
|
95
108
|
results.push(txHash);
|
|
96
|
-
(0, ttd_core_1.log_info)(`Transaction sent`, { provider: provider.name, order_trace_id, txHash });
|
|
97
109
|
}
|
|
98
110
|
catch (error) {
|
|
99
111
|
errors.push(`${provider.name}: ${error.message}`);
|
|
100
|
-
(0, ttd_core_1.log_info)(`Transaction failed`, { provider: provider.name, order_trace_id, error: error.message });
|
|
112
|
+
(0, ttd_core_1.log_info)(`Transaction send failed`, { provider: provider.name, order_trace_id, error: error.message });
|
|
101
113
|
}
|
|
102
114
|
})));
|
|
103
|
-
if (
|
|
104
|
-
|
|
115
|
+
if (results.length > 0) {
|
|
116
|
+
return results;
|
|
105
117
|
}
|
|
106
118
|
if (errors.some(e => e.includes('bundle already exist') || e.includes('already known'))) {
|
|
107
119
|
return results;
|
|
108
120
|
}
|
|
109
|
-
if (
|
|
110
|
-
throw new Error(`
|
|
121
|
+
if (errors.some(e => e.includes('nonce'))) {
|
|
122
|
+
throw new Error(`Nonce error: ${JSON.stringify(errors)}`);
|
|
111
123
|
}
|
|
112
|
-
|
|
124
|
+
throw new Error(`Send failed: ${JSON.stringify(errors)}`);
|
|
113
125
|
});
|
|
114
126
|
}
|
|
115
127
|
}
|
package/dist/ws_client.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export declare class BscSendTxProxy {
|
|
2
2
|
private wsUrl;
|
|
3
3
|
private ws;
|
|
4
|
+
private clientName;
|
|
5
|
+
private connected;
|
|
6
|
+
private pendingQueue;
|
|
4
7
|
constructor();
|
|
5
8
|
sendTransaction(builder: '48club' | 'bloxroute', pair: string, mainTx: string, tipTx: string, _48spSign?: string): void;
|
|
6
9
|
}
|
package/dist/ws_client.js
CHANGED
|
@@ -2,17 +2,43 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BscSendTxProxy = void 0;
|
|
4
4
|
const ttd_core_1 = require("@clonegod/ttd-core");
|
|
5
|
+
const appconfig_1 = require("./appconfig");
|
|
6
|
+
const logger = (0, ttd_core_1.createLogger)(__filename);
|
|
5
7
|
class BscSendTxProxy {
|
|
6
8
|
constructor() {
|
|
7
|
-
|
|
9
|
+
this.connected = false;
|
|
10
|
+
this.pendingQueue = [];
|
|
11
|
+
const host = appconfig_1.envArgs.send_tx_ws_host;
|
|
8
12
|
this.wsUrl = `ws://${host}:${ttd_core_1.SERVICE_PORT.SEND_TX_WS}/bsc/send_tx`;
|
|
13
|
+
this.clientName = process.env.APP_NAME
|
|
14
|
+
|| process.env.name
|
|
15
|
+
|| (process.env.pm_id ? `pm2-${process.env.pm_id}` : `pid-${process.pid}`);
|
|
9
16
|
this.ws = new ttd_core_1.WebSocketClient(this.wsUrl);
|
|
10
|
-
this.ws.onOpen(() =>
|
|
11
|
-
|
|
17
|
+
this.ws.onOpen(() => {
|
|
18
|
+
this.connected = true;
|
|
19
|
+
this.ws.send(JSON.stringify({ type: 'hello', clientName: this.clientName }));
|
|
20
|
+
const flushed = this.pendingQueue.length;
|
|
21
|
+
if (flushed > 0) {
|
|
22
|
+
for (const msg of this.pendingQueue) {
|
|
23
|
+
this.ws.send(msg);
|
|
24
|
+
}
|
|
25
|
+
this.pendingQueue.length = 0;
|
|
26
|
+
}
|
|
27
|
+
logger.info(`BscSendTxProxy connected: ${this.wsUrl}, client=${this.clientName}, flushed=${flushed}`);
|
|
28
|
+
});
|
|
29
|
+
this.ws.onMessage((message) => logger.debug(`BscSendTxProxy response`, message));
|
|
12
30
|
this.ws.connect();
|
|
13
31
|
}
|
|
14
32
|
sendTransaction(builder, pair, mainTx, tipTx, _48spSign = null) {
|
|
15
|
-
|
|
33
|
+
const msg = JSON.stringify({ builder, pair, mainTx, tipTx, _48spSign });
|
|
34
|
+
if (this.connected) {
|
|
35
|
+
this.ws.send(msg);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
if (this.pendingQueue.length < 100) {
|
|
39
|
+
this.pendingQueue.push(msg);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
16
42
|
}
|
|
17
43
|
}
|
|
18
44
|
exports.BscSendTxProxy = BscSendTxProxy;
|
package/dist/ws_server.js
CHANGED
|
@@ -11,6 +11,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
require('dotenv').config();
|
|
13
13
|
const ttd_core_1 = require("@clonegod/ttd-core");
|
|
14
|
+
const appconfig_1 = require("./appconfig");
|
|
15
|
+
(0, ttd_core_1.setCoreEnv)(appconfig_1.envArgs);
|
|
14
16
|
const ws_1 = require("ws");
|
|
15
17
|
const _48club_1 = require("./_48club");
|
|
16
18
|
const bloxroute_1 = require("./bloxroute");
|
|
@@ -18,6 +20,8 @@ class BscSendTxWebSocketServer {
|
|
|
18
20
|
constructor(appConfig, serverPort = ttd_core_1.SERVICE_PORT.SEND_TX_WS) {
|
|
19
21
|
this.wss = null;
|
|
20
22
|
this.latestBlockNumber = 0;
|
|
23
|
+
this.clientNames = new WeakMap();
|
|
24
|
+
this.connectedCount = 0;
|
|
21
25
|
this._48clubWsSender = null;
|
|
22
26
|
this.bloxrouteWsSender = null;
|
|
23
27
|
this.appConfig = appConfig;
|
|
@@ -33,19 +37,41 @@ class BscSendTxWebSocketServer {
|
|
|
33
37
|
this.initSenders();
|
|
34
38
|
}
|
|
35
39
|
initSenders() {
|
|
36
|
-
if (
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
if (appconfig_1.envArgs._48club_ws_url) {
|
|
41
|
+
try {
|
|
42
|
+
this._48clubWsSender = new _48club_1._48ClubWsSender();
|
|
43
|
+
this._48clubWsSender.connect();
|
|
44
|
+
(0, ttd_core_1.log_info)(`[WS_SERVER] 48Club upstream WS client started → ${appconfig_1.envArgs._48club_ws_url}`);
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
(0, ttd_core_1.log_error)('[WS_SERVER] 48Club upstream init failed', e instanceof Error ? e : new Error(String(e)));
|
|
48
|
+
}
|
|
39
49
|
}
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
|
|
50
|
+
if (appconfig_1.envArgs.bloxroute_ws_url && appconfig_1.envArgs.blox_auth_key) {
|
|
51
|
+
try {
|
|
52
|
+
this.bloxrouteWsSender = new bloxroute_1.BloXRouteWsSender();
|
|
53
|
+
this.bloxrouteWsSender.connect();
|
|
54
|
+
(0, ttd_core_1.log_info)(`[WS_SERVER] BloxRoute upstream WS client started → ${appconfig_1.envArgs.bloxroute_ws_url}`);
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
(0, ttd_core_1.log_error)('[WS_SERVER] BloxRoute upstream init failed', e instanceof Error ? e : new Error(String(e)));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else if (appconfig_1.envArgs.bloxroute_ws_url && !appconfig_1.envArgs.blox_auth_key) {
|
|
61
|
+
(0, ttd_core_1.log_info)(`[WS_SERVER] BloxRoute upstream skipped: BLOX_AUTH_KEY 未配置`);
|
|
43
62
|
}
|
|
44
63
|
}
|
|
45
64
|
handleMessage(ws, message) {
|
|
46
65
|
var _a, _b;
|
|
47
66
|
try {
|
|
48
|
-
const
|
|
67
|
+
const parsed = JSON.parse(message);
|
|
68
|
+
if (parsed.type === 'hello') {
|
|
69
|
+
this.clientNames.set(ws, parsed.clientName || 'unknown');
|
|
70
|
+
this.connectedCount++;
|
|
71
|
+
(0, ttd_core_1.log_info)(`[WS_SERVER] client connected: ${parsed.clientName}, total=${this.connectedCount}`);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const request = parsed;
|
|
49
75
|
if (!request.mainTx || !request.builder || !request.tipTx) {
|
|
50
76
|
ws.send(JSON.stringify({ error: 'Missing required fields: mainTx, builder, tipTx' }));
|
|
51
77
|
return;
|
|
@@ -71,9 +97,12 @@ class BscSendTxWebSocketServer {
|
|
|
71
97
|
return;
|
|
72
98
|
this.wss = new ws_1.WebSocketServer({ port: this.serverPort });
|
|
73
99
|
this.wss.on('connection', (ws) => {
|
|
74
|
-
(0, ttd_core_1.log_info)(`[WS_SERVER] client connected`);
|
|
75
100
|
ws.on('message', (msg) => this.handleMessage(ws, msg.toString()));
|
|
76
|
-
ws.on('close', () =>
|
|
101
|
+
ws.on('close', () => {
|
|
102
|
+
const name = this.clientNames.get(ws) || 'unknown';
|
|
103
|
+
this.connectedCount = Math.max(0, this.connectedCount - 1);
|
|
104
|
+
(0, ttd_core_1.log_info)(`[WS_SERVER] client disconnected: ${name}, total=${this.connectedCount}`);
|
|
105
|
+
});
|
|
77
106
|
ws.on('error', (err) => (0, ttd_core_1.log_error)(`[WS_SERVER] ws error`, err));
|
|
78
107
|
});
|
|
79
108
|
(0, ttd_core_1.log_info)(`[WS_SERVER] started on port ${this.serverPort}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clonegod/ttd-bsc-send-tx",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.5",
|
|
4
4
|
"description": "BSC 交易发送模块(HTTP直发 + WS bundle 转发)",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"push": "npm run build && npm publish"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@clonegod/ttd-core": "3.
|
|
16
|
-
"axios": "
|
|
15
|
+
"@clonegod/ttd-core": "3.1.52",
|
|
16
|
+
"axios": "1.15.0",
|
|
17
17
|
"dotenv": "^16.4.7",
|
|
18
18
|
"ethers": "^5.8.0",
|
|
19
19
|
"ws": "^8.18.3"
|