@clonegod/ttd-sol-common 1.0.33 → 1.0.34

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.
@@ -0,0 +1,10 @@
1
+ export declare const MAX_GAS_FEE: number;
2
+ export declare const ONE_MILLION = 1000000;
3
+ export declare enum COMMITMENT_LEVEL {
4
+ PROCESSED = "processed",
5
+ CONFIRMED = "confirmed",
6
+ _FINALIZED = "finalized"
7
+ }
8
+ export declare enum LOCAL_EVENT_NAME {
9
+ EVENT_POOL_ACCOUNT_CHANGE = "EVENT_POOL_ACCOUNT_CHANGE"
10
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LOCAL_EVENT_NAME = exports.COMMITMENT_LEVEL = exports.ONE_MILLION = exports.MAX_GAS_FEE = void 0;
4
+ const web3_js_1 = require("@solana/web3.js");
5
+ exports.MAX_GAS_FEE = web3_js_1.LAMPORTS_PER_SOL / 1000;
6
+ exports.ONE_MILLION = 1000000;
7
+ var COMMITMENT_LEVEL;
8
+ (function (COMMITMENT_LEVEL) {
9
+ COMMITMENT_LEVEL["PROCESSED"] = "processed";
10
+ COMMITMENT_LEVEL["CONFIRMED"] = "confirmed";
11
+ COMMITMENT_LEVEL["_FINALIZED"] = "finalized";
12
+ })(COMMITMENT_LEVEL || (exports.COMMITMENT_LEVEL = COMMITMENT_LEVEL = {}));
13
+ var LOCAL_EVENT_NAME;
14
+ (function (LOCAL_EVENT_NAME) {
15
+ LOCAL_EVENT_NAME["EVENT_POOL_ACCOUNT_CHANGE"] = "EVENT_POOL_ACCOUNT_CHANGE";
16
+ })(LOCAL_EVENT_NAME || (exports.LOCAL_EVENT_NAME = LOCAL_EVENT_NAME = {}));
@@ -0,0 +1,22 @@
1
+ import { OrderMessageType, PriceMessageType, StandardPoolInfoType, TradeRuntimeType } from "@clonegod/ttd-common";
2
+ import { CHAIN_ID, DEX_ID } from "@clonegod/ttd-common/dist";
3
+ import { Connection } from "@solana/web3.js";
4
+ import { SolanaTradeRuntimeType } from "./types";
5
+ export declare class TradeContext {
6
+ connection: Connection;
7
+ trade_runtime: TradeRuntimeType;
8
+ solana_trade_runtime: SolanaTradeRuntimeType;
9
+ price_msg: PriceMessageType;
10
+ order_msg: OrderMessageType;
11
+ order_trace_id: string;
12
+ group_id: string;
13
+ chain_id: CHAIN_ID;
14
+ dex_id: DEX_ID;
15
+ pool_id: string;
16
+ fee_rate: string;
17
+ pool_info: StandardPoolInfoType;
18
+ aToB: boolean;
19
+ slippage_bps: number;
20
+ constructor(price_msg: PriceMessageType, order_msg: OrderMessageType);
21
+ init(trade_runtime: TradeRuntimeType): Promise<void>;
22
+ }
@@ -0,0 +1,41 @@
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.TradeContext = void 0;
13
+ const dist_1 = require("@clonegod/ttd-common/dist");
14
+ const send_tx_1 = require("../send_tx");
15
+ class TradeContext {
16
+ constructor(price_msg, order_msg) {
17
+ this.price_msg = price_msg;
18
+ this.order_msg = order_msg;
19
+ this.order_trace_id = order_msg.order_trace_id;
20
+ }
21
+ init(trade_runtime) {
22
+ return __awaiter(this, void 0, void 0, function* () {
23
+ this.trade_runtime = trade_runtime;
24
+ let { group_id, unique_orderbook_id } = this.order_msg;
25
+ this.group_id = group_id;
26
+ let unique_orderbook_id_obj = (0, dist_1.parse_unique_orderbook_id)(unique_orderbook_id);
27
+ this.chain_id = dist_1.CHAIN_ID[unique_orderbook_id_obj.chain_id];
28
+ this.dex_id = dist_1.DEX_ID[unique_orderbook_id_obj.dex_id];
29
+ this.pool_id = unique_orderbook_id_obj.pool_id;
30
+ this.fee_rate = unique_orderbook_id_obj.fee_rate;
31
+ this.pool_info = this.trade_runtime.pair_dex.pool_info_list.find(e => e.pool_address === this.pool_id);
32
+ if (!this.pool_info) {
33
+ throw new Error(`Not found pool_info! pool_id=${this.pool_id}, pool_info_list=${JSON.stringify(this.trade_runtime.pair_dex.pool_info_list)}`);
34
+ }
35
+ this.slippage_bps = Math.min(100, Math.max(30, this.trade_runtime.settings.slippage_bps));
36
+ this.aToB = this.pool_info.is_reverse_token ? !this.order_msg.aToB : this.order_msg.aToB;
37
+ this.solana_trade_runtime = (0, send_tx_1.create_solana_trade_runtime)(this.connection, this.trade_runtime, this.pool_info);
38
+ });
39
+ }
40
+ }
41
+ exports.TradeContext = TradeContext;
@@ -0,0 +1,3 @@
1
+ export * from './constants';
2
+ export * from './context';
3
+ export * from './types';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./constants"), exports);
18
+ __exportStar(require("./context"), exports);
19
+ __exportStar(require("./types"), exports);
@@ -0,0 +1,31 @@
1
+ import { StandardTokenInfoType, TradeRuntimeType } from "@clonegod/ttd-common";
2
+ import { Connection } from "@solana/web3.js";
3
+ export interface StandardSwapDetailType {
4
+ success: boolean;
5
+ error_code: string;
6
+ wallet: string;
7
+ txid: string;
8
+ block_time: number;
9
+ block_number: number;
10
+ pool_address: string;
11
+ tokenA: TokenBalChangeType;
12
+ tokenB: TokenBalChangeType;
13
+ tx_price: string;
14
+ gas_fee: GasFeeType;
15
+ }
16
+ export interface TokenBalChangeType extends StandardTokenInfoType {
17
+ pre_bal: number;
18
+ post_bal: number;
19
+ change: string;
20
+ }
21
+ export interface GasFeeType {
22
+ base_fee: number;
23
+ priority_fee: number;
24
+ total_fee: number;
25
+ }
26
+ export interface SolanaTradeRuntimeType extends TradeRuntimeType {
27
+ connection: Connection;
28
+ priority_fee: number;
29
+ cu_price: number;
30
+ cu_limit: number;
31
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,4 @@
1
+ /// <reference types="node" />
2
+ import { StandardPoolInfoType } from "@clonegod/ttd-common";
3
+ import EventEmitter from "events";
4
+ export declare const subscribe_pool_change_by_geyser: (geyser_ws_url: string, pool_list: StandardPoolInfoType[], eventEmitter: EventEmitter) => Promise<void>;
@@ -0,0 +1,93 @@
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.subscribe_pool_change_by_geyser = void 0;
16
+ const dist_1 = require("@clonegod/ttd-common/dist");
17
+ const ws_1 = __importDefault(require("ws"));
18
+ const constants_1 = require("../common/constants");
19
+ const subscribe_pool_change_by_geyser = (geyser_ws_url, pool_list, eventEmitter) => __awaiter(void 0, void 0, void 0, function* () {
20
+ if ((0, dist_1.isEmpty)(geyser_ws_url)) {
21
+ (0, dist_1.log_warn)(`geyser_ws_url is empty, cann't subscribe`);
22
+ return;
23
+ }
24
+ if ((0, dist_1.isEmpty)(pool_list)) {
25
+ (0, dist_1.log_warn)(`pool_list is empty, nothing to subscribe`);
26
+ return;
27
+ }
28
+ yield (0, dist_1.sleep)(1000);
29
+ var ws_client = new ws_1.default(geyser_ws_url);
30
+ function subscribe_account_change(ws_client, pool) {
31
+ (0, dist_1.log_info)(`subscribe: ${pool.pool_name} -> ${pool.pool_address}`);
32
+ const request = {
33
+ jsonrpc: '2.0',
34
+ id: 420,
35
+ method: 'accountSubscribe',
36
+ params: [
37
+ pool.pool_address,
38
+ {
39
+ encoding: 'jsonParsed',
40
+ commitment: constants_1.COMMITMENT_LEVEL.PROCESSED,
41
+ },
42
+ ],
43
+ };
44
+ ws_client.send(JSON.stringify(request));
45
+ }
46
+ ws_client.on('open', function open() {
47
+ (0, dist_1.log_info)(`WebSocket is open`);
48
+ pool_list.forEach((pool) => {
49
+ subscribe_account_change(ws_client, pool);
50
+ });
51
+ });
52
+ ws_client.on('message', function incoming(data) {
53
+ return __awaiter(this, void 0, void 0, function* () {
54
+ (0, dist_1.log_info)(`Received Geyser Message`);
55
+ let messageStr = '';
56
+ try {
57
+ messageStr = data.toString('utf8');
58
+ if (dist_1.LOG.trace) {
59
+ (0, dist_1.log_trace)(`Received msg:`, messageStr);
60
+ }
61
+ if (messageStr == '{}') {
62
+ (0, dist_1.log_info)(`receive empty message, something wrong! exit ...`);
63
+ ws_client.close();
64
+ }
65
+ const messageObj = JSON.parse(messageStr);
66
+ if (messageObj['id']) {
67
+ (0, dist_1.log_info)(`accountSubscribe success!`, messageStr);
68
+ return;
69
+ }
70
+ else {
71
+ const res_data = messageObj['params']['result']['value']['data'];
72
+ let data_buff = Buffer.from(res_data[0], res_data[1]);
73
+ eventEmitter.emit(constants_1.LOCAL_EVENT_NAME.EVENT_POOL_ACCOUNT_CHANGE, data_buff);
74
+ }
75
+ }
76
+ catch (err) {
77
+ (0, dist_1.log_error)(`Failed to parse JSON: ${messageStr}`, err);
78
+ ws_client.close();
79
+ }
80
+ });
81
+ });
82
+ ws_client.on('error', function error(err) {
83
+ (0, dist_1.log_error)(`WebSocket error:`, err);
84
+ ws_client.close();
85
+ });
86
+ ws_client.on('close', function close() {
87
+ return __awaiter(this, void 0, void 0, function* () {
88
+ (0, dist_1.log_warn)(`Socket is closed. Reconnect will be attempted in few seconds`);
89
+ (0, exports.subscribe_pool_change_by_geyser)(geyser_ws_url, pool_list, eventEmitter);
90
+ });
91
+ });
92
+ });
93
+ exports.subscribe_pool_change_by_geyser = subscribe_pool_change_by_geyser;
@@ -3,7 +3,7 @@
3
3
  import { BlockhashWithExpiryBlockHeight, VersionedTransaction, AddressLookupTableAccount, Transaction, TransactionInstruction, TransactionSignature, Commitment, PublicKey, AccountInfo, GetLatestBlockhashConfig, RpcResponseAndContext, SignatureResult, Blockhash, Connection, ParsedAccountData, SendOptions, Signer, SerializeConfig } from '@solana/web3.js';
4
4
  import { DAS } from './types/das-types';
5
5
  import { GetPriorityFeeEstimateRequest, GetPriorityFeeEstimateResponse, JitoRegion, PollTransactionOptions, SmartTransactionContext, HeliusSendOptions } from './types';
6
- import { SolanaTradeRuntimeType } from '../context';
6
+ import { SolanaTradeRuntimeType } from '../common';
7
7
  export type SendAndConfirmTransactionResponse = {
8
8
  signature: TransactionSignature;
9
9
  confirmResponse: RpcResponseAndContext<SignatureResult>;
@@ -17,7 +17,7 @@ const web3_js_1 = require("@solana/web3.js");
17
17
  const bs58_1 = __importDefault(require("bs58"));
18
18
  const axios_1 = __importDefault(require("axios"));
19
19
  const types_1 = require("./types");
20
- const get_signature_1 = require("../get_signature");
20
+ const get_signature_1 = require("../send_tx/get_signature");
21
21
  const dist_1 = require("@clonegod/ttd-common/dist");
22
22
  class RpcClient {
23
23
  constructor(connection, id) {
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- export * from './constants';
2
- export * from './context';
3
- export * from './strategy_util';
1
+ export * from './common';
4
2
  export * from './helius_geyser_ws';
5
- export * from './send_transaction';
3
+ export * from './send_tx';
4
+ export * from './trade';
package/dist/index.js CHANGED
@@ -14,8 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./constants"), exports);
18
- __exportStar(require("./context"), exports);
19
- __exportStar(require("./strategy_util"), exports);
17
+ __exportStar(require("./common"), exports);
20
18
  __exportStar(require("./helius_geyser_ws"), exports);
21
- __exportStar(require("./send_transaction"), exports);
19
+ __exportStar(require("./send_tx"), exports);
20
+ __exportStar(require("./trade"), exports);
@@ -0,0 +1,2 @@
1
+ import { Transaction, VersionedTransaction } from '@solana/web3.js';
2
+ export declare function getSignature(transaction: Transaction | VersionedTransaction): string;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getSignature = void 0;
7
+ const bs58_1 = __importDefault(require("bs58"));
8
+ function getSignature(transaction) {
9
+ const signature = 'signature' in transaction ? transaction.signature : transaction.signatures[0];
10
+ if (!signature) {
11
+ throw new Error('Missing transaction signature, the transaction was not signed by the fee payer');
12
+ }
13
+ return bs58_1.default.encode(signature);
14
+ }
15
+ exports.getSignature = getSignature;
@@ -0,0 +1,3 @@
1
+ export * from './get_signature';
2
+ export * from './send_transaction';
3
+ export * from './strategy_util';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./get_signature"), exports);
18
+ __exportStar(require("./send_transaction"), exports);
19
+ __exportStar(require("./strategy_util"), exports);
@@ -0,0 +1,14 @@
1
+ import { SendOptions, Signer, TransactionInstruction } from "@solana/web3.js";
2
+ import { Helius } from "../helius_sdk_v1.4.0";
3
+ import { SolanaTradeRuntimeType } from '../common/types';
4
+ export declare class HeliusClient {
5
+ signers: Signer[];
6
+ sendOptions: SendOptions;
7
+ cluster: string;
8
+ helius_mainnet: Helius;
9
+ helius_staked: Helius;
10
+ constructor(signers: Signer[]);
11
+ send_transaction(solana_trade_runtime: SolanaTradeRuntimeType, instructions: TransactionInstruction[]): Promise<string>;
12
+ private send_smart_transaction;
13
+ private send_transaction_by_jito;
14
+ }
@@ -0,0 +1,79 @@
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.HeliusClient = void 0;
13
+ const dist_1 = require("@clonegod/ttd-common/dist");
14
+ const helius_sdk_v1_4_0_1 = require("../helius_sdk_v1.4.0");
15
+ const strategy_util_1 = require("./strategy_util");
16
+ class HeliusClient {
17
+ constructor(signers) {
18
+ this.cluster = 'mainnet-beta';
19
+ this.signers = signers;
20
+ this.sendOptions = {
21
+ skipPreflight: true,
22
+ maxRetries: 0
23
+ };
24
+ let helius_api_key = process.env.HELIUS_API_KEY;
25
+ let helius_mainnet_endpoint = `https://mainnet.helius-rpc.com/?api-key=${helius_api_key}`;
26
+ let helius_staked_endpoint = `https://staked.helius-rpc.com?api-key=${helius_api_key}`;
27
+ this.helius_mainnet = new helius_sdk_v1_4_0_1.Helius('', this.cluster, 'helius-sdk', helius_mainnet_endpoint);
28
+ this.helius_staked = new helius_sdk_v1_4_0_1.Helius('', this.cluster, 'helius-sdk', helius_staked_endpoint);
29
+ }
30
+ send_transaction(solana_trade_runtime, instructions) {
31
+ return __awaiter(this, void 0, void 0, function* () {
32
+ let txid = '';
33
+ let { broadcast_type, speed } = solana_trade_runtime.settings.strategy;
34
+ if (broadcast_type === 'rpc') {
35
+ let use_staked_endpint = speed === 'turbo' || speed === 'ultra';
36
+ txid = yield this.send_smart_transaction(solana_trade_runtime, instructions, use_staked_endpint);
37
+ }
38
+ else if (broadcast_type === 'jito') {
39
+ txid = yield this.send_transaction_by_jito(solana_trade_runtime, instructions);
40
+ }
41
+ else {
42
+ throw new Error(`Not support broadcast_type: ${broadcast_type}`);
43
+ }
44
+ return txid;
45
+ });
46
+ }
47
+ send_smart_transaction(solana_trade_runtime, instructions, use_staked_endpint) {
48
+ return __awaiter(this, void 0, void 0, function* () {
49
+ (0, dist_1.log_info)(`send_smart_transaction, start`);
50
+ let start_time = Date.now();
51
+ let rpc = use_staked_endpint ? this.helius_staked.rpc : this.helius_mainnet.rpc;
52
+ let txid = yield rpc.sendSmartTransaction(solana_trade_runtime, instructions, this.signers, [], this.sendOptions);
53
+ (0, dist_1.log_info)(`send_smart_transaction, end`, {
54
+ txid,
55
+ use_staked_endpint,
56
+ take_time: Date.now() - start_time
57
+ });
58
+ return txid;
59
+ });
60
+ }
61
+ send_transaction_by_jito(solana_trade_runtime, instructions) {
62
+ return __awaiter(this, void 0, void 0, function* () {
63
+ (0, dist_1.log_info)(`send_transaction_by_jito, start`);
64
+ let start_time = Date.now();
65
+ let tipAmount = solana_trade_runtime.priority_fee;
66
+ let jito_region = (0, strategy_util_1.get_jito_region)();
67
+ let rpc = this.helius_mainnet.rpc;
68
+ let txid = yield rpc.sendSmartTransactionWithTip(solana_trade_runtime, instructions, this.signers, [], tipAmount, jito_region);
69
+ (0, dist_1.log_info)(`send_transaction_by_jito, end`, {
70
+ tipAmount,
71
+ jito_region,
72
+ txid,
73
+ take_time: Date.now() - start_time
74
+ });
75
+ return txid;
76
+ });
77
+ }
78
+ }
79
+ exports.HeliusClient = HeliusClient;
@@ -0,0 +1,7 @@
1
+ import { StandardPoolInfoType, TradeRuntimeType, TradeStrategyType } from "@clonegod/ttd-common";
2
+ import { JitoRegion } from "../helius_sdk_v1.4.0";
3
+ import { Connection } from "@solana/web3.js";
4
+ import { SolanaTradeRuntimeType } from "../common/types";
5
+ export declare function create_solana_trade_runtime(connection: Connection, trade_runtime: TradeRuntimeType, pool_info: StandardPoolInfoType): SolanaTradeRuntimeType;
6
+ export declare function calculate_gas_fee(trade_strategy: TradeStrategyType): number;
7
+ export declare function get_jito_region(): JitoRegion;
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.get_jito_region = exports.calculate_gas_fee = exports.create_solana_trade_runtime = void 0;
4
+ const dist_1 = require("@clonegod/ttd-common/dist");
5
+ const constants_1 = require("../common/constants");
6
+ function create_solana_trade_runtime(connection, trade_runtime, pool_info) {
7
+ let trade_strategy = trade_runtime.settings.strategy;
8
+ let { cu_limit } = pool_info;
9
+ if (isNaN(cu_limit) || cu_limit < 50000) {
10
+ cu_limit = 50000;
11
+ }
12
+ let priority_fee = calculate_gas_fee(trade_strategy);
13
+ let cu_price = Math.ceil(priority_fee * constants_1.ONE_MILLION / cu_limit);
14
+ (0, dist_1.log_info)(`trade_strategy & gas`, {
15
+ trade_strategy,
16
+ priority_fee,
17
+ cu_limit,
18
+ cu_price
19
+ });
20
+ let solana_trade_runtime = Object.assign(Object.assign({}, trade_runtime), { connection,
21
+ priority_fee,
22
+ cu_limit,
23
+ cu_price });
24
+ return solana_trade_runtime;
25
+ }
26
+ exports.create_solana_trade_runtime = create_solana_trade_runtime;
27
+ function calculate_gas_fee(trade_strategy) {
28
+ let { speed, fee_mode, fee_exact, fee_max_cap, } = trade_strategy;
29
+ let gas_fee = 1000;
30
+ switch (fee_mode) {
31
+ case "exact":
32
+ gas_fee = get_excat_fee_by_speed(speed, fee_exact);
33
+ break;
34
+ case "max_cap":
35
+ gas_fee = get_dynamic_fee_by_speed(speed, 50000, fee_max_cap);
36
+ break;
37
+ default:
38
+ throw new Error(`Not support fee_mode: ${fee_mode}`);
39
+ }
40
+ return gas_fee;
41
+ }
42
+ exports.calculate_gas_fee = calculate_gas_fee;
43
+ function get_excat_fee_by_speed(speed, fee_exact) {
44
+ let factor = 1;
45
+ if (speed === 'fast') {
46
+ factor = 1;
47
+ }
48
+ if (speed === 'turbo') {
49
+ factor = 2;
50
+ }
51
+ if (speed === 'ultra') {
52
+ factor = 5;
53
+ }
54
+ return fee_exact * factor;
55
+ }
56
+ function get_dynamic_fee_by_speed(speed, estimate_priority_fee, fee_max_cap) {
57
+ let factor = 1;
58
+ if (speed === 'fast') {
59
+ factor = 1;
60
+ }
61
+ if (speed === 'turbo') {
62
+ factor = 2;
63
+ }
64
+ if (speed === 'ultra') {
65
+ factor = 5;
66
+ }
67
+ return Math.min(estimate_priority_fee * factor, fee_max_cap);
68
+ }
69
+ function get_jito_region() {
70
+ let jito_region;
71
+ let server_info = (0, dist_1.getServerInfo)();
72
+ switch (server_info.region) {
73
+ case 'fra':
74
+ jito_region = 'Frankfurt';
75
+ break;
76
+ case 'virginia':
77
+ jito_region = 'NY';
78
+ break;
79
+ case 'jp':
80
+ jito_region = 'Tokyo';
81
+ break;
82
+ default:
83
+ jito_region = 'Default';
84
+ }
85
+ (0, dist_1.log_debug)(`get_jito_region`, {
86
+ server_info,
87
+ jito_region
88
+ });
89
+ return jito_region;
90
+ }
91
+ exports.get_jito_region = get_jito_region;
@@ -0,0 +1,4 @@
1
+ import { TradeContext } from "../common/context";
2
+ export declare abstract class AbastrcatTrade {
3
+ abstract execute(context: TradeContext): Promise<string>;
4
+ }
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AbastrcatTrade = void 0;
4
+ class AbastrcatTrade {
5
+ }
6
+ exports.AbastrcatTrade = AbastrcatTrade;
@@ -0,0 +1,3 @@
1
+ export * from './abstract_trade';
2
+ export * from './tx_result_check';
3
+ export * from './tx_result_parse';
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./abstract_trade"), exports);
18
+ __exportStar(require("./tx_result_check"), exports);
19
+ __exportStar(require("./tx_result_parse"), exports);
@@ -0,0 +1,27 @@
1
+ /// <reference types="node" />
2
+ import { OrderMessageType, PriceMessageType, StandardPoolInfoType, TradeResultType } from "@clonegod/ttd-common";
3
+ import { Connection, PublicKey } from "@solana/web3.js";
4
+ import { EventEmitter } from 'events';
5
+ import { TradeContext } from "../common/context";
6
+ import { StandardSwapDetailType } from "../common/types";
7
+ import { TransactionResultParser } from "./tx_result_parse";
8
+ export declare class TransactionResultChecker {
9
+ env_args: any;
10
+ event_emitter: EventEmitter;
11
+ connection: Connection;
12
+ wallet: PublicKey;
13
+ context: TradeContext;
14
+ group_id: string;
15
+ txid: string;
16
+ trace_id: string;
17
+ price_msg: PriceMessageType;
18
+ order_msg: OrderMessageType;
19
+ pool_info: StandardPoolInfoType;
20
+ check_count: number;
21
+ transactionParser: TransactionResultParser;
22
+ constructor(env_args: any, event_emitter: EventEmitter, context: TradeContext, txid: string);
23
+ init_tx_status(): this;
24
+ check(): Promise<void>;
25
+ check_tx_result_interval(): Promise<void>;
26
+ map_swap_result_to_tx_result(swap_result: StandardSwapDetailType): TradeResultType;
27
+ }
@@ -0,0 +1,179 @@
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.TransactionResultChecker = void 0;
13
+ const dist_1 = require("@clonegod/ttd-common/dist");
14
+ const web3_js_1 = require("@solana/web3.js");
15
+ const constants_1 = require("../common/constants");
16
+ const tx_result_parse_1 = require("./tx_result_parse");
17
+ class TransactionResultChecker {
18
+ constructor(env_args, event_emitter, context, txid) {
19
+ this.env_args = env_args;
20
+ this.event_emitter = event_emitter;
21
+ this.context = context;
22
+ this.group_id = context.group_id;
23
+ this.connection = context.solana_trade_runtime.connection;
24
+ this.wallet = new web3_js_1.PublicKey(context.trade_runtime.wallet.public_key);
25
+ this.txid = txid;
26
+ this.price_msg = context.price_msg;
27
+ this.order_msg = context.order_msg;
28
+ this.pool_info = context.pool_info;
29
+ this.trace_id = context.order_msg.order_trace_id;
30
+ this.check_count = 0;
31
+ this.transactionParser = new tx_result_parse_1.TransactionResultParser(this.env_args, this.wallet, this.event_emitter);
32
+ }
33
+ init_tx_status() {
34
+ let empty_trade_result = JSON.parse(JSON.stringify({
35
+ group_id: this.context.group_id,
36
+ txid: this.txid
37
+ }));
38
+ this.event_emitter.emit(dist_1.TRANSACTION_STATE_PROCESSING, empty_trade_result);
39
+ return this;
40
+ }
41
+ check() {
42
+ return __awaiter(this, void 0, void 0, function* () {
43
+ this.check_tx_result_interval();
44
+ });
45
+ }
46
+ check_tx_result_interval() {
47
+ return __awaiter(this, void 0, void 0, function* () {
48
+ const check_start_time = Date.now();
49
+ const check_interval = 1000;
50
+ const check_timeout = 30 * 1000;
51
+ const intervalId = setInterval(() => __awaiter(this, void 0, void 0, function* () {
52
+ this.check_count += 1;
53
+ (0, dist_1.log_info)(`check transaction start: seq=[${this.check_count}], txhash= ${this.txid}, trace_id=${this.trace_id}`);
54
+ try {
55
+ if (Date.now() - check_start_time < check_timeout) {
56
+ let tx_info = yield this.connection.getParsedTransaction(this.txid, {
57
+ commitment: constants_1.COMMITMENT_LEVEL.CONFIRMED,
58
+ maxSupportedTransactionVersion: 0,
59
+ });
60
+ if ((0, dist_1.isEmpty)(tx_info)) {
61
+ return;
62
+ }
63
+ clearInterval(intervalId);
64
+ let swap_result = this.transactionParser.parse_transaction_data(tx_info, this.pool_info);
65
+ let trade_result = this.map_swap_result_to_tx_result(swap_result);
66
+ if (trade_result.success) {
67
+ this.event_emitter.emit(dist_1.TRANSACTION_STATE_SUCCESS, trade_result);
68
+ }
69
+ else {
70
+ this.event_emitter.emit(dist_1.TRANSACTION_STATE_FAILED, trade_result);
71
+ }
72
+ setTimeout(() => {
73
+ console.log('<====================================================');
74
+ console.dir(trade_result, { depth: 8 });
75
+ console.log('====================================================>');
76
+ }, 0);
77
+ }
78
+ else {
79
+ clearInterval(intervalId);
80
+ }
81
+ }
82
+ catch (err) {
83
+ (0, dist_1.log_error)('parse transaction error!', err);
84
+ }
85
+ }), check_interval);
86
+ });
87
+ }
88
+ map_swap_result_to_tx_result(swap_result) {
89
+ let { success, error_code, wallet, block_number, block_time: order_block_time, txid, tx_price, tokenA, tokenB, gas_fee } = swap_result;
90
+ let { pool_name, is_reverse_token } = this.pool_info;
91
+ let { chain_id, dex_id, unique_orderbook_id, pair, price_id, time: quote_time, ask, bid } = this.price_msg;
92
+ let { group_id, unique_order_msg_id, order_send_time, order_recv_time, order_submit_time, aToB } = this.order_msg;
93
+ let order_price = aToB ? bid.price : ask.price;
94
+ let server_info = (0, dist_1.getServerInfo)();
95
+ let total_order_time = (order_block_time + 500) - order_recv_time;
96
+ let order_end_time = Date.now();
97
+ let start_time = order_recv_time;
98
+ let end_time = order_end_time;
99
+ let total_time = total_order_time;
100
+ let time = {
101
+ block_time: quote_time.block_time,
102
+ stream_time: quote_time.stream_time,
103
+ quote_start_time: quote_time.quote_start_time,
104
+ quote_end_time: quote_time.quote_end_time,
105
+ price_time: quote_time.price_time,
106
+ total_quote_time: quote_time.total_quote_time,
107
+ order_send_time,
108
+ order_recv_time,
109
+ order_submit_time,
110
+ order_block_time,
111
+ total_order_time,
112
+ order_end_time,
113
+ };
114
+ let broadcast = [];
115
+ let trade_strategy = this.context.solana_trade_runtime.settings.strategy;
116
+ let send_type = trade_strategy.broadcast_type;
117
+ if (send_type === 'rpc') {
118
+ send_type = trade_strategy.speed === 'fast' ? 'mainnet' : 'mainnet-premium';
119
+ }
120
+ broadcast.push({
121
+ rpc: {
122
+ read: 'qn',
123
+ write: 'qn'
124
+ },
125
+ type: send_type,
126
+ fee: gas_fee
127
+ });
128
+ let trade_balance_change = {
129
+ tokenA: {
130
+ symbol: tokenA.symbol,
131
+ address: tokenA.address,
132
+ pre_bal: tokenA.pre_bal,
133
+ post_bal: tokenA.post_bal,
134
+ change: Number(tokenA.change),
135
+ decimals: tokenA.decimals,
136
+ },
137
+ tokenB: {
138
+ symbol: tokenB.symbol,
139
+ address: tokenB.address,
140
+ pre_bal: tokenB.pre_bal,
141
+ post_bal: tokenB.post_bal,
142
+ change: Number(tokenB.change),
143
+ decimals: tokenB.decimals,
144
+ },
145
+ };
146
+ if (is_reverse_token) {
147
+ let { tokenA, tokenB } = trade_balance_change;
148
+ trade_balance_change.tokenA = tokenB;
149
+ trade_balance_change.tokenB = tokenA;
150
+ }
151
+ let trade_extra_info = {
152
+ time,
153
+ broadcast,
154
+ server_info,
155
+ };
156
+ const trade_result = {
157
+ success,
158
+ error_code,
159
+ start_time,
160
+ end_time,
161
+ total_time,
162
+ group_id,
163
+ wallet,
164
+ chain_id,
165
+ pair,
166
+ dex_id,
167
+ txid,
168
+ unique_orderbook_id,
169
+ unique_order_msg_id,
170
+ order_price,
171
+ aToB,
172
+ tx_price,
173
+ balance: trade_balance_change,
174
+ execution: trade_extra_info,
175
+ };
176
+ return trade_result;
177
+ }
178
+ }
179
+ exports.TransactionResultChecker = TransactionResultChecker;
@@ -0,0 +1,14 @@
1
+ /// <reference types="node" />
2
+ import { StandardPoolInfoType } from '@clonegod/ttd-common';
3
+ import { ParsedTransactionWithMeta, PublicKey, TokenBalance } from '@solana/web3.js';
4
+ import { EventEmitter } from 'events';
5
+ import { StandardSwapDetailType } from '../common/types';
6
+ export declare class TransactionResultParser {
7
+ env_args: any;
8
+ event_emitter: EventEmitter;
9
+ wallet_pubkey: PublicKey;
10
+ constructor(env_args: any, wallet_pubkey: PublicKey, event_emitter: EventEmitter);
11
+ parse_transaction_data(txData: ParsedTransactionWithMeta, pool_info: StandardPoolInfoType): StandardSwapDetailType;
12
+ getTokenBalance(owner: string, mint: string, tokenBalances: TokenBalance[]): number;
13
+ }
14
+ export declare const parse_tx_failed_error_code: (dex_id_list: string[], tx_failed_error_msg: string) => string;
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parse_tx_failed_error_code = exports.TransactionResultParser = void 0;
4
+ const dist_1 = require("@clonegod/ttd-common/dist");
5
+ class TransactionResultParser {
6
+ constructor(env_args, wallet_pubkey, event_emitter) {
7
+ this.env_args = env_args;
8
+ this.wallet_pubkey = wallet_pubkey;
9
+ this.event_emitter = event_emitter;
10
+ }
11
+ parse_transaction_data(txData, pool_info) {
12
+ let success = true;
13
+ let error_code = '';
14
+ let { blockTime, meta, transaction, slot } = txData;
15
+ if (meta.err) {
16
+ success = false;
17
+ error_code = (0, exports.parse_tx_failed_error_code)(this.env_args.dex_id_list, JSON.stringify({
18
+ txid: transaction.signatures,
19
+ err: meta.err,
20
+ logMessages: meta.logMessages
21
+ }));
22
+ }
23
+ const { pool_address, tokenA, tokenB, is_reverse_token } = pool_info;
24
+ let txid = transaction.signatures[0];
25
+ const owner = this.wallet_pubkey.toBase58();
26
+ const { preTokenBalances, postTokenBalances, preBalances, postBalances } = meta;
27
+ const tokenA_PreBalance = this.getTokenBalance(owner, tokenA.address, preTokenBalances);
28
+ const tokenA_PostBalance = this.getTokenBalance(owner, tokenA.address, postTokenBalances);
29
+ const tokenB_PreBalance = this.getTokenBalance(owner, tokenB.address, preTokenBalances);
30
+ const tokenB_PostBalance = this.getTokenBalance(owner, tokenB.address, postTokenBalances);
31
+ blockTime = blockTime * 1000 || 0;
32
+ const tokenAChange = Number((tokenA_PostBalance - tokenA_PreBalance).toFixed(tokenA.decimals));
33
+ const tokenBChange = Number((tokenB_PostBalance - tokenB_PreBalance).toFixed(tokenB.decimals));
34
+ let price = "";
35
+ if (success) {
36
+ if (is_reverse_token) {
37
+ price = Math.abs(tokenAChange / tokenBChange).toFixed(tokenA.decimals);
38
+ }
39
+ else {
40
+ price = Math.abs(tokenBChange / tokenAChange).toFixed(tokenB.decimals);
41
+ }
42
+ }
43
+ const base_fee = 5000;
44
+ const total_fee = preBalances[0] - postBalances[0];
45
+ const priority_fee = total_fee - base_fee;
46
+ let gas_fee = {
47
+ base_fee,
48
+ priority_fee,
49
+ total_fee
50
+ };
51
+ const tradeResult = {
52
+ success,
53
+ error_code,
54
+ wallet: owner,
55
+ block_time: blockTime,
56
+ block_number: slot,
57
+ txid,
58
+ pool_address,
59
+ tokenA: Object.assign(Object.assign({}, tokenA), { pre_bal: tokenA_PreBalance, post_bal: tokenA_PostBalance, change: tokenAChange.toString() }),
60
+ tokenB: Object.assign(Object.assign({}, tokenB), { pre_bal: tokenB_PreBalance, post_bal: tokenB_PostBalance, change: tokenBChange.toString() }),
61
+ tx_price: price,
62
+ gas_fee
63
+ };
64
+ return tradeResult;
65
+ }
66
+ getTokenBalance(owner, mint, tokenBalances) {
67
+ var _a, _b;
68
+ const balance = (_b = (_a = tokenBalances === null || tokenBalances === void 0 ? void 0 : tokenBalances.find((e) => e.owner === owner && e.mint == mint)) === null || _a === void 0 ? void 0 : _a.uiTokenAmount) === null || _b === void 0 ? void 0 : _b.uiAmount;
69
+ if (typeof balance !== 'undefined' && balance !== null) {
70
+ return balance;
71
+ }
72
+ return 0;
73
+ }
74
+ }
75
+ exports.TransactionResultParser = TransactionResultParser;
76
+ const parse_tx_failed_error_code = (dex_id_list, tx_failed_error_msg) => {
77
+ (0, dist_1.log_info)(`parse_tx_failed_error_code`, {
78
+ dex_id_list,
79
+ tx_failed_error_msg
80
+ });
81
+ let err_code = "";
82
+ if (dex_id_list.includes(dist_1.DEX_ID.RAYDIUM_AMM)) {
83
+ err_code = parse_raydium_failure(tx_failed_error_msg);
84
+ }
85
+ else if (dex_id_list.includes(dist_1.DEX_ID.ORCA_CLMM)) {
86
+ err_code = parse_orca_failure(tx_failed_error_msg);
87
+ }
88
+ if (!err_code) {
89
+ err_code = dist_1.TradeErrorCodeType.UNKOWN;
90
+ }
91
+ return err_code;
92
+ };
93
+ exports.parse_tx_failed_error_code = parse_tx_failed_error_code;
94
+ function parse_raydium_failure(error_msg) {
95
+ if (error_msg.includes('0x28')) {
96
+ return dist_1.TradeErrorCodeType.InsufficientFunds;
97
+ }
98
+ if (error_msg.includes('0x1e') || error_msg.includes('exceeds desired slippage limit')) {
99
+ return dist_1.TradeErrorCodeType.AmountOutBelowMinimum;
100
+ }
101
+ return null;
102
+ }
103
+ function parse_orca_failure(error_msg) {
104
+ if (error_msg.includes('0x1]') || error_msg.includes('insufficient funds')) {
105
+ return dist_1.TradeErrorCodeType.InsufficientFunds;
106
+ }
107
+ if (error_msg.includes('0x1794') || error_msg.includes('below minimum threshold')) {
108
+ return dist_1.TradeErrorCodeType.AmountOutBelowMinimum;
109
+ }
110
+ if (error_msg.includes('0xbc4') || error_msg.includes('expected this account to be already initialized')) {
111
+ return dist_1.TradeErrorCodeType.AccountNotInitialized;
112
+ }
113
+ if (error_msg.includes('0x1787') || error_msg.includes('Invalid tick array sequence')) {
114
+ return dist_1.TradeErrorCodeType.InvalidTickArraySequence;
115
+ }
116
+ return null;
117
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clonegod/ttd-sol-common",
3
- "version": "1.0.33",
3
+ "version": "1.0.34",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "types/index.d.ts",
@@ -13,7 +13,8 @@
13
13
  "push": "npm run build && npm publish"
14
14
  },
15
15
  "dependencies": {
16
- "@clonegod/ttd-common": "1.0.135",
16
+ "@clonegod/ttd-common": "1.0.145",
17
+ "@solana/web3.js": "1.91.6",
17
18
  "@irys/sdk": "^0.2.10",
18
19
  "@metaplex-foundation/mpl-token-metadata": "^2.5.2",
19
20
  "axios": "^1.2.3",