@clonegod/ttd-bsc-send-tx 1.0.0

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.
Files changed (50) hide show
  1. package/README.md +40 -0
  2. package/dist/_48club/http.d.ts +9 -0
  3. package/dist/_48club/http.js +69 -0
  4. package/dist/_48club/index.d.ts +4 -0
  5. package/dist/_48club/index.js +11 -0
  6. package/dist/_48club/member.d.ts +1 -0
  7. package/dist/_48club/member.js +21 -0
  8. package/dist/_48club/sp_signature.d.ts +4 -0
  9. package/dist/_48club/sp_signature.js +27 -0
  10. package/dist/_48club/ws.d.ts +9 -0
  11. package/dist/_48club/ws.js +63 -0
  12. package/dist/blockrazor/index.d.ts +7 -0
  13. package/dist/blockrazor/index.js +67 -0
  14. package/dist/bloxroute/index.d.ts +1 -0
  15. package/dist/bloxroute/index.js +5 -0
  16. package/dist/bloxroute/ws.d.ts +10 -0
  17. package/dist/bloxroute/ws.js +65 -0
  18. package/dist/constants.d.ts +5 -0
  19. package/dist/constants.js +9 -0
  20. package/dist/index.d.ts +2 -0
  21. package/dist/index.js +7 -0
  22. package/dist/rpc/index.d.ts +6 -0
  23. package/dist/rpc/index.js +47 -0
  24. package/dist/transaction_sender.d.ts +9 -0
  25. package/dist/transaction_sender.js +116 -0
  26. package/dist/types/index.d.ts +8 -0
  27. package/dist/types/index.js +2 -0
  28. package/dist/ws_client.d.ts +6 -0
  29. package/dist/ws_client.js +18 -0
  30. package/dist/ws_server.d.ts +1 -0
  31. package/dist/ws_server.js +93 -0
  32. package/package.json +29 -0
  33. package/scripts/deploy.sh +29 -0
  34. package/scripts/start-ttd-bsc-send-tx-ws.sh +24 -0
  35. package/src/_48club/http.ts +60 -0
  36. package/src/_48club/index.ts +4 -0
  37. package/src/_48club/member.ts +19 -0
  38. package/src/_48club/sp_signature.ts +28 -0
  39. package/src/_48club/ws.ts +47 -0
  40. package/src/blockrazor/index.ts +57 -0
  41. package/src/bloxroute/index.ts +1 -0
  42. package/src/bloxroute/ws.ts +53 -0
  43. package/src/constants.ts +5 -0
  44. package/src/index.ts +2 -0
  45. package/src/rpc/index.ts +42 -0
  46. package/src/transaction_sender.ts +123 -0
  47. package/src/types/index.ts +8 -0
  48. package/src/ws_client.ts +22 -0
  49. package/src/ws_server.ts +104 -0
  50. package/tsconfig.json +25 -0
package/README.md ADDED
@@ -0,0 +1,40 @@
1
+ ## BSC - Submit tx to Builder
2
+
3
+ ### 48club
4
+ > https://docs.48.club/puissant-builder/send-privatetransaction
5
+ > https://docs.48.club/puissant-builder/send-bundle
6
+
7
+ #### Endpoint
8
+ - https://puissant-builder.48.club/
9
+ - wss://puissant-builder.48.club/
10
+
11
+ #### EOA address
12
+ 0x4848489f0b2BEdd788c696e2D79b6b69D7484848
13
+
14
+
15
+
16
+ ### BlockRazor
17
+ > https://blockrazor.gitbook.io/blockrazor/tc/bsc/block-builder/send-privatetransaction
18
+ > https://blockrazor.gitbook.io/blockrazor/tc/bsc/block-builder/send-bundle
19
+
20
+ #### Endpoint
21
+ - https://tokyo.builder.blockrazor.io
22
+
23
+ #### EOA address
24
+ 0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20
25
+
26
+
27
+
28
+ ### BloXRoute
29
+ > https://docs.bloxroute.com/bsc-and-eth/apis/frontrunning-protection/bsc-private-transactions
30
+ > https://docs.bloxroute.com/bsc-and-eth/apis/transaction-bundles/bundle-submission/bsc-bundle-submission
31
+
32
+ #### Endpoint
33
+ - https://api.blxrbdn.com
34
+ - wss://api.blxrbdn.com/ws
35
+
36
+
37
+ ### EOA address
38
+ 0x6374Ca2da5646C73Eb444aB99780495d61035f9b
39
+
40
+
@@ -0,0 +1,9 @@
1
+ export declare class _48ClubTrade {
2
+ private rpcUrl;
3
+ constructor();
4
+ sendPrivateTransactionWith48SP(signedTx: string): Promise<string>;
5
+ sendBundle(params: {
6
+ txs: string[];
7
+ }): Promise<string>;
8
+ get48SPSignature(txs: string[]): Promise<string>;
9
+ }
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports._48ClubTrade = void 0;
16
+ const axios_1 = __importDefault(require("axios"));
17
+ const sp_signature_1 = require("./sp_signature");
18
+ const member_1 = require("./member");
19
+ class _48ClubTrade {
20
+ constructor() {
21
+ this.rpcUrl = process.env._48CLUB_RPC_URL || 'https://puissant-bsc.48.club';
22
+ }
23
+ sendPrivateTransactionWith48SP(signedTx) {
24
+ return __awaiter(this, void 0, void 0, function* () {
25
+ const spSign = yield this.get48SPSignature([signedTx]);
26
+ 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' }
32
+ });
33
+ if (response.data.error) {
34
+ throw new Error(`48club private tx: ${response.data.error.message}`);
35
+ }
36
+ return response.data.result;
37
+ });
38
+ }
39
+ sendBundle(params) {
40
+ return __awaiter(this, void 0, void 0, function* () {
41
+ const currentTimestamp = Math.floor(Date.now() / 1000);
42
+ const spSign = yield this.get48SPSignature(params.txs);
43
+ const response = yield axios_1.default.post(this.rpcUrl, {
44
+ jsonrpc: "2.0", id: 1,
45
+ method: "eth_sendBundle",
46
+ params: [{
47
+ txs: params.txs,
48
+ maxTimestamp: currentTimestamp + 2,
49
+ '48spSign': spSign
50
+ }]
51
+ }, {
52
+ headers: { 'Content-Type': 'application/json' }
53
+ });
54
+ if (response.data.error) {
55
+ throw new Error(`48club bundle: ${response.data.error.message}`);
56
+ }
57
+ return response.data.result;
58
+ });
59
+ }
60
+ get48SPSignature(txs) {
61
+ return __awaiter(this, void 0, void 0, function* () {
62
+ const privateKey = (0, member_1.get_48club_sp_private_key)();
63
+ if (!privateKey)
64
+ return '';
65
+ return sp_signature_1.SoulPointSignature.generate48SPSignature(privateKey, txs);
66
+ });
67
+ }
68
+ }
69
+ exports._48ClubTrade = _48ClubTrade;
@@ -0,0 +1,4 @@
1
+ export { _48ClubTrade } from './http';
2
+ export { _48ClubWsSender } from './ws';
3
+ export { SoulPointSignature } from './sp_signature';
4
+ export { get_48club_sp_private_key } from './member';
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.get_48club_sp_private_key = exports.SoulPointSignature = exports._48ClubWsSender = exports._48ClubTrade = void 0;
4
+ var http_1 = require("./http");
5
+ Object.defineProperty(exports, "_48ClubTrade", { enumerable: true, get: function () { return http_1._48ClubTrade; } });
6
+ var ws_1 = require("./ws");
7
+ Object.defineProperty(exports, "_48ClubWsSender", { enumerable: true, get: function () { return ws_1._48ClubWsSender; } });
8
+ var sp_signature_1 = require("./sp_signature");
9
+ Object.defineProperty(exports, "SoulPointSignature", { enumerable: true, get: function () { return sp_signature_1.SoulPointSignature; } });
10
+ var member_1 = require("./member");
11
+ Object.defineProperty(exports, "get_48club_sp_private_key", { enumerable: true, get: function () { return member_1.get_48club_sp_private_key; } });
@@ -0,0 +1 @@
1
+ export declare const get_48club_sp_private_key: () => string | null;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.get_48club_sp_private_key = void 0;
4
+ const ttd_core_1 = require("@clonegod/ttd-core");
5
+ var _48club_sp_wallet_private_key = null;
6
+ const get_48club_sp_private_key = () => {
7
+ if (_48club_sp_wallet_private_key) {
8
+ return _48club_sp_wallet_private_key;
9
+ }
10
+ try {
11
+ const wallet = (0, ttd_core_1.load_wallet)(process.env._48CLUB_SP_WALLET_ID || 'TTD-PAYMENT');
12
+ console.log('Load 48club SP wallet success, wallet address:', wallet.public_key);
13
+ _48club_sp_wallet_private_key = wallet.private_key;
14
+ return _48club_sp_wallet_private_key;
15
+ }
16
+ catch (error) {
17
+ console.error('Load 48club SP wallet failed:' + error.message);
18
+ return null;
19
+ }
20
+ };
21
+ exports.get_48club_sp_private_key = get_48club_sp_private_key;
@@ -0,0 +1,4 @@
1
+ export declare class SoulPointSignature {
2
+ static generate48SPSignature(privateKey: string, txs: string[]): string;
3
+ static verify48SPSignature(signature: string, txs: string[], expectedSignerAddress: string): boolean;
4
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SoulPointSignature = void 0;
4
+ const ethers_1 = require("ethers");
5
+ class SoulPointSignature {
6
+ static generate48SPSignature(privateKey, txs) {
7
+ const wallet = new ethers_1.ethers.Wallet(privateKey);
8
+ const txHashes = txs.map(tx => tx.startsWith('0x') ? ethers_1.ethers.utils.keccak256(tx) : tx);
9
+ const concatenatedHashes = ethers_1.ethers.utils.concat(txHashes);
10
+ const messageHash = ethers_1.ethers.utils.keccak256(concatenatedHashes);
11
+ const signature = wallet._signingKey().signDigest(messageHash);
12
+ return signature.compact;
13
+ }
14
+ static verify48SPSignature(signature, txs, expectedSignerAddress) {
15
+ try {
16
+ const txHashes = txs.map(tx => tx.startsWith('0x') ? ethers_1.ethers.utils.keccak256(tx) : tx);
17
+ const concatenatedHashes = ethers_1.ethers.utils.concat(txHashes);
18
+ const messageHash = ethers_1.ethers.utils.keccak256(concatenatedHashes);
19
+ const recoveredAddress = ethers_1.ethers.utils.recoverAddress(messageHash, signature);
20
+ return recoveredAddress.toLowerCase() === expectedSignerAddress.toLowerCase();
21
+ }
22
+ catch (_a) {
23
+ return false;
24
+ }
25
+ }
26
+ }
27
+ exports.SoulPointSignature = SoulPointSignature;
@@ -0,0 +1,9 @@
1
+ import { BscSendTxRequestType } from '../types';
2
+ export declare class _48ClubWsSender {
3
+ private wsClient;
4
+ private wsUrl;
5
+ constructor();
6
+ connect(): void;
7
+ isConnected(): boolean;
8
+ sendTransaction(request: BscSendTxRequestType): Promise<void>;
9
+ }
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports._48ClubWsSender = void 0;
13
+ const ttd_core_1 = require("@clonegod/ttd-core");
14
+ class _48ClubWsSender {
15
+ constructor() {
16
+ this.wsClient = null;
17
+ this.wsUrl = process.env._48CLUB_WS_URL || 'wss://puissant-builder.48.club/';
18
+ }
19
+ connect() {
20
+ var _a;
21
+ if ((_a = this.wsClient) === null || _a === void 0 ? void 0 : _a.isConnected())
22
+ return;
23
+ if (this.wsClient) {
24
+ this.wsClient.disconnect();
25
+ this.wsClient = null;
26
+ }
27
+ this.wsClient = new ttd_core_1.WebSocketClient(this.wsUrl, { reconnectInterval: 1000 });
28
+ this.wsClient.onOpen(() => (0, ttd_core_1.log_info)(`[48club-ws] connected`));
29
+ this.wsClient.onMessage((msg) => (0, ttd_core_1.log_info)(`[48club-ws] response:`, msg));
30
+ this.wsClient.connect();
31
+ }
32
+ isConnected() {
33
+ var _a;
34
+ return ((_a = this.wsClient) === null || _a === void 0 ? void 0 : _a.isConnected()) || false;
35
+ }
36
+ sendTransaction(request) {
37
+ return __awaiter(this, void 0, void 0, function* () {
38
+ if (!this.isConnected()) {
39
+ (0, ttd_core_1.log_warn)('[48club-ws] not connected');
40
+ return;
41
+ }
42
+ if (!request.tipTx) {
43
+ (0, ttd_core_1.log_warn)('[48club-ws] tipTx required for bundle');
44
+ return;
45
+ }
46
+ const currentTimestamp = Math.floor(Date.now() / 1000);
47
+ const bundleParams = {
48
+ txs: [request.mainTx, request.tipTx],
49
+ maxTimestamp: currentTimestamp + 2,
50
+ };
51
+ if (request.blockNumber > 0)
52
+ bundleParams.maxBlockNumber = request.blockNumber + 2;
53
+ if (request._48spSign)
54
+ bundleParams['48spSign'] = request._48spSign;
55
+ this.wsClient.send(JSON.stringify({
56
+ jsonrpc: '2.0', id: '1',
57
+ method: 'eth_sendBundle',
58
+ params: [bundleParams]
59
+ }));
60
+ });
61
+ }
62
+ }
63
+ exports._48ClubWsSender = _48ClubWsSender;
@@ -0,0 +1,7 @@
1
+ export declare class BlockRazorTrade {
2
+ private rpcUrl;
3
+ private authToken;
4
+ constructor();
5
+ sendPrivateTransaction(signedTx: string): Promise<string>;
6
+ sendBundle(transactions: string[]): Promise<string>;
7
+ }
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.BlockRazorTrade = void 0;
16
+ const ttd_core_1 = require("@clonegod/ttd-core");
17
+ const axios_1 = __importDefault(require("axios"));
18
+ class BlockRazorTrade {
19
+ constructor() {
20
+ this.rpcUrl = process.env.BLOCKRAZOR_RPC_URL || 'https://rpc.blockrazor.builders';
21
+ this.authToken = process.env.BLOCKRAZOR_AUTH_TOKEN || '';
22
+ }
23
+ sendPrivateTransaction(signedTx) {
24
+ return __awaiter(this, void 0, void 0, function* () {
25
+ try {
26
+ const response = yield axios_1.default.post(this.rpcUrl, {
27
+ jsonrpc: "2.0", id: "1",
28
+ method: "eth_sendPrivateTransaction",
29
+ params: [signedTx]
30
+ }, {
31
+ headers: { 'Content-Type': 'application/json', 'Authorization': this.authToken }
32
+ });
33
+ if (response.data.error) {
34
+ throw new Error(`${response.data.error.code} - ${response.data.error.message}`);
35
+ }
36
+ return response.data.result;
37
+ }
38
+ catch (error) {
39
+ (0, ttd_core_1.log_error)('blockrazor sendPrivateTransaction failed', error);
40
+ throw error;
41
+ }
42
+ });
43
+ }
44
+ sendBundle(transactions) {
45
+ return __awaiter(this, void 0, void 0, function* () {
46
+ try {
47
+ const currentTimestamp = Math.floor(Date.now() / 1000);
48
+ const response = yield axios_1.default.post(this.rpcUrl, {
49
+ jsonrpc: "2.0", id: "1",
50
+ method: "eth_sendBundle",
51
+ params: [{ txs: transactions, maxTimestamp: currentTimestamp + 5 }]
52
+ }, {
53
+ headers: { 'Content-Type': 'application/json', 'Authorization': this.authToken }
54
+ });
55
+ if (response.data.error) {
56
+ throw new Error(`Bundle: ${response.data.error.message}`);
57
+ }
58
+ return response.data.result;
59
+ }
60
+ catch (error) {
61
+ (0, ttd_core_1.log_error)('blockrazor sendBundle failed', error);
62
+ throw error;
63
+ }
64
+ });
65
+ }
66
+ }
67
+ exports.BlockRazorTrade = BlockRazorTrade;
@@ -0,0 +1 @@
1
+ export { BloXRouteWsSender } from './ws';
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BloXRouteWsSender = void 0;
4
+ var ws_1 = require("./ws");
5
+ Object.defineProperty(exports, "BloXRouteWsSender", { enumerable: true, get: function () { return ws_1.BloXRouteWsSender; } });
@@ -0,0 +1,10 @@
1
+ import { BscSendTxRequestType } from '../types';
2
+ export declare class BloXRouteWsSender {
3
+ private wsClient;
4
+ private wsUrl;
5
+ private authToken;
6
+ constructor();
7
+ connect(): void;
8
+ isConnected(): boolean;
9
+ sendTransaction(request: BscSendTxRequestType): Promise<void>;
10
+ }
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.BloXRouteWsSender = void 0;
13
+ const ttd_core_1 = require("@clonegod/ttd-core");
14
+ class BloXRouteWsSender {
15
+ constructor() {
16
+ this.wsClient = null;
17
+ this.wsUrl = process.env.BLOXROUTE_WS_URL || 'wss://api.blxrbdn.com/ws';
18
+ this.authToken = process.env.BLOX_AUTH_KEY || '';
19
+ }
20
+ connect() {
21
+ var _a;
22
+ if ((_a = this.wsClient) === null || _a === void 0 ? void 0 : _a.isConnected())
23
+ return;
24
+ if (this.wsClient) {
25
+ this.wsClient.disconnect();
26
+ this.wsClient = null;
27
+ }
28
+ const headers = {};
29
+ if (this.authToken)
30
+ headers['Authorization'] = this.authToken;
31
+ this.wsClient = new ttd_core_1.WebSocketClient(this.wsUrl, { headers, reconnectInterval: 1000 });
32
+ this.wsClient.onOpen(() => (0, ttd_core_1.log_info)(`[bloxroute-ws] connected`));
33
+ this.wsClient.onMessage((msg) => (0, ttd_core_1.log_info)(`[bloxroute-ws] response:`, msg));
34
+ this.wsClient.connect();
35
+ }
36
+ isConnected() {
37
+ var _a;
38
+ return ((_a = this.wsClient) === null || _a === void 0 ? void 0 : _a.isConnected()) || false;
39
+ }
40
+ sendTransaction(request) {
41
+ return __awaiter(this, void 0, void 0, function* () {
42
+ if (!this.isConnected()) {
43
+ (0, ttd_core_1.log_warn)('[bloxroute-ws] not connected');
44
+ return;
45
+ }
46
+ if (!request.tipTx) {
47
+ (0, ttd_core_1.log_warn)('[bloxroute-ws] tipTx required for bundle');
48
+ return;
49
+ }
50
+ const targetBlockNumber = request.blockNumber + 4;
51
+ this.wsClient.send(JSON.stringify({
52
+ id: "1",
53
+ method: "blxr_submit_bundle",
54
+ params: {
55
+ transaction: [request.mainTx, request.tipTx],
56
+ blockchain_network: "BSC-Mainnet",
57
+ block_number: `0x${targetBlockNumber.toString(16)}`,
58
+ max_timestamp: Math.floor(Date.now() / 1000) + 2,
59
+ mev_builders: { "all": "" }
60
+ }
61
+ }));
62
+ });
63
+ }
64
+ }
65
+ exports.BloXRouteWsSender = BloXRouteWsSender;
@@ -0,0 +1,5 @@
1
+ export declare enum BSC_EOA_ADDRESS {
2
+ BLOCKRAZOR = "0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20",
3
+ _48CLUB = "0x4848489f0b2BEdd788c696e2D79b6b69D7484848",
4
+ BLXR = "0x74c5F8C6ffe41AD4789602BDB9a48E6Cad623520"
5
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BSC_EOA_ADDRESS = void 0;
4
+ var BSC_EOA_ADDRESS;
5
+ (function (BSC_EOA_ADDRESS) {
6
+ BSC_EOA_ADDRESS["BLOCKRAZOR"] = "0x1266C6bE60392A8Ff346E8d5ECCd3E69dD9c5F20";
7
+ BSC_EOA_ADDRESS["_48CLUB"] = "0x4848489f0b2BEdd788c696e2D79b6b69D7484848";
8
+ BSC_EOA_ADDRESS["BLXR"] = "0x74c5F8C6ffe41AD4789602BDB9a48E6Cad623520";
9
+ })(BSC_EOA_ADDRESS || (exports.BSC_EOA_ADDRESS = BSC_EOA_ADDRESS = {}));
@@ -0,0 +1,2 @@
1
+ export { TransactionSender } from './transaction_sender';
2
+ export { BSC_EOA_ADDRESS } from './constants';
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BSC_EOA_ADDRESS = exports.TransactionSender = void 0;
4
+ var transaction_sender_1 = require("./transaction_sender");
5
+ Object.defineProperty(exports, "TransactionSender", { enumerable: true, get: function () { return transaction_sender_1.TransactionSender; } });
6
+ var constants_1 = require("./constants");
7
+ Object.defineProperty(exports, "BSC_EOA_ADDRESS", { enumerable: true, get: function () { return constants_1.BSC_EOA_ADDRESS; } });
@@ -0,0 +1,6 @@
1
+ export declare class BscMainnetRpc {
2
+ private url;
3
+ private headers;
4
+ constructor(rpc_endpoint: string);
5
+ eth_sendRawTransaction(signedTx: string): Promise<string>;
6
+ }
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.BscMainnetRpc = void 0;
13
+ const ttd_core_1 = require("@clonegod/ttd-core");
14
+ class BscMainnetRpc {
15
+ constructor(rpc_endpoint) {
16
+ this.url = rpc_endpoint || process.env.BSC_RPC_ENDPOINT || '';
17
+ this.headers = new Headers();
18
+ this.headers.append("Content-Type", "application/json");
19
+ }
20
+ eth_sendRawTransaction(signedTx) {
21
+ return __awaiter(this, void 0, void 0, function* () {
22
+ setTimeout(() => __awaiter(this, void 0, void 0, function* () {
23
+ console.log(`Sending transaction to ${this.url}`);
24
+ const raw = JSON.stringify({
25
+ jsonrpc: "2.0",
26
+ method: "eth_sendRawTransaction",
27
+ params: [signedTx],
28
+ id: 1
29
+ });
30
+ const requestOptions = {
31
+ method: 'POST',
32
+ headers: this.headers,
33
+ body: raw,
34
+ redirect: 'follow'
35
+ };
36
+ const response = yield fetch(this.url, requestOptions);
37
+ const result = yield response.json();
38
+ if (result.error) {
39
+ (0, ttd_core_1.log_warn)(result.error.message);
40
+ }
41
+ return result.result;
42
+ }), 0);
43
+ return '';
44
+ });
45
+ }
46
+ }
47
+ exports.BscMainnetRpc = BscMainnetRpc;
@@ -0,0 +1,9 @@
1
+ import { AppConfig } from '@clonegod/ttd-core';
2
+ export declare class TransactionSender {
3
+ private rpc;
4
+ private blockRazor;
5
+ private _48Club;
6
+ private sendBundleProxy;
7
+ constructor(appConfig: AppConfig);
8
+ sendTransaction(signedMainTx: string, eoa_tip_transaction: (eoa_address: string) => Promise<string>, order_trace_id: string, pair?: string, only_bundle?: boolean): Promise<string[]>;
9
+ }
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.TransactionSender = void 0;
13
+ const ttd_core_1 = require("@clonegod/ttd-core");
14
+ const rpc_1 = require("./rpc");
15
+ const blockrazor_1 = require("./blockrazor");
16
+ const _48club_1 = require("./_48club");
17
+ const ws_client_1 = require("./ws_client");
18
+ const constants_1 = require("./constants");
19
+ class TransactionSender {
20
+ constructor(appConfig) {
21
+ this.rpc = new rpc_1.BscMainnetRpc(appConfig.env_args.rpc_endpoint);
22
+ this.blockRazor = new blockrazor_1.BlockRazorTrade();
23
+ this._48Club = new _48club_1._48ClubTrade();
24
+ this.sendBundleProxy = new ws_client_1.BscSendTxProxy();
25
+ }
26
+ sendTransaction(signedMainTx_1, eoa_tip_transaction_1, order_trace_id_1) {
27
+ return __awaiter(this, arguments, void 0, function* (signedMainTx, eoa_tip_transaction, order_trace_id, pair = '', only_bundle = false) {
28
+ const rpcProviders = [
29
+ {
30
+ name: 'Default RPC',
31
+ enable: process.env.SEND_TX_DEFAULT_RPC_PRIVATE === 'true',
32
+ is_bundle: false,
33
+ send: () => __awaiter(this, void 0, void 0, function* () { return this.rpc.eth_sendRawTransaction(signedMainTx); }),
34
+ },
35
+ {
36
+ name: 'BlockRazor HTTP Private',
37
+ enable: process.env.SEND_TX_BLOCKRAZOR_PRIVATE === 'true',
38
+ is_bundle: false,
39
+ send: () => __awaiter(this, void 0, void 0, function* () { return this.blockRazor.sendPrivateTransaction(signedMainTx); }),
40
+ },
41
+ {
42
+ name: 'BlockRazor HTTP Bundle',
43
+ enable: process.env.SEND_TX_BLOCKRAZOR_BUNDLE === 'true',
44
+ is_bundle: true,
45
+ send: () => __awaiter(this, void 0, void 0, function* () {
46
+ const bundle = [signedMainTx, yield eoa_tip_transaction(constants_1.BSC_EOA_ADDRESS.BLOCKRAZOR)];
47
+ return this.blockRazor.sendBundle(bundle);
48
+ }),
49
+ },
50
+ {
51
+ name: '48Club HTTP Private',
52
+ enable: process.env.SEND_TX_48CLUB_PRIVATE === 'true',
53
+ is_bundle: false,
54
+ send: () => __awaiter(this, void 0, void 0, function* () { return this._48Club.sendPrivateTransactionWith48SP(signedMainTx); }),
55
+ },
56
+ {
57
+ name: '48Club HTTP Bundle',
58
+ enable: process.env.SEND_TX_48CLUB_BUNDLE === 'true',
59
+ is_bundle: true,
60
+ send: () => __awaiter(this, void 0, void 0, function* () {
61
+ const bundle = [signedMainTx, yield eoa_tip_transaction(constants_1.BSC_EOA_ADDRESS._48CLUB)];
62
+ return this._48Club.sendBundle({ txs: bundle });
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';
84
+ }),
85
+ },
86
+ ];
87
+ const results = [];
88
+ const errors = [];
89
+ yield Promise.all(rpcProviders
90
+ .filter(p => p.enable)
91
+ .filter(p => only_bundle ? p.is_bundle : true)
92
+ .map((provider) => __awaiter(this, void 0, void 0, function* () {
93
+ try {
94
+ const txHash = yield provider.send();
95
+ results.push(txHash);
96
+ (0, ttd_core_1.log_info)(`Transaction sent`, { provider: provider.name, order_trace_id, txHash });
97
+ }
98
+ catch (error) {
99
+ errors.push(`${provider.name}: ${error.message}`);
100
+ (0, ttd_core_1.log_info)(`Transaction failed`, { provider: provider.name, order_trace_id, error: error.message });
101
+ }
102
+ })));
103
+ if (errors.some(e => e.includes('nonce'))) {
104
+ throw new Error(`Nonce error: ${JSON.stringify(errors)}`);
105
+ }
106
+ if (errors.some(e => e.includes('bundle already exist') || e.includes('already known'))) {
107
+ return results;
108
+ }
109
+ if (results.length === 0 || errors.length > 0) {
110
+ throw new Error(`Send failed: ${JSON.stringify(errors)}`);
111
+ }
112
+ return results;
113
+ });
114
+ }
115
+ }
116
+ exports.TransactionSender = TransactionSender;