@clonegod/ttd-core 2.0.7 → 2.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import EventEmitter from "events";
2
- import { TradeRuntimeType } from "../../types";
2
+ import { StandardTokenInfoType, TradeRuntimeType } from "../../types";
3
3
  import { ArbCache, ArbEventSubscriber } from "../cache";
4
4
  import { EnvArgs } from "./env_args";
5
5
  export declare class AppConfig extends EventEmitter {
@@ -12,4 +12,6 @@ export declare class AppConfig extends EventEmitter {
12
12
  constructor();
13
13
  init(): Promise<void>;
14
14
  subscribe_config_change(): Promise<void>;
15
+ cache_token_market_price(token_info_with_price: StandardTokenInfoType, ttl?: number): Promise<void>;
16
+ get_token_market_price(symbol: string): Promise<StandardTokenInfoType>;
15
17
  }
@@ -22,6 +22,7 @@ class AppConfig extends events_1.default {
22
22
  this.env_args = new env_args_1.EnvArgs();
23
23
  let { chain_id, app_name, dex_id } = this.env_args;
24
24
  this.app_full_name = `${chain_id}_${dex_id}_${app_name}`;
25
+ global.app_config = this;
25
26
  }
26
27
  init() {
27
28
  return __awaiter(this, void 0, void 0, function* () {
@@ -55,5 +56,16 @@ class AppConfig extends events_1.default {
55
56
  yield this.arb_event_subscriber.subscribe_config_change_event(refresh_trade_runtime);
56
57
  });
57
58
  }
59
+ cache_token_market_price(token_info_with_price_1) {
60
+ return __awaiter(this, arguments, void 0, function* (token_info_with_price, ttl = -1) {
61
+ token_info_with_price.update_time = (0, __1.getCurDateTime)();
62
+ yield this.arb_cache.cache_token_market_price(token_info_with_price, ttl);
63
+ });
64
+ }
65
+ get_token_market_price(symbol) {
66
+ return __awaiter(this, void 0, void 0, function* () {
67
+ return yield this.arb_cache.get_token_market_price(symbol);
68
+ });
69
+ }
58
70
  }
59
71
  exports.AppConfig = AppConfig;
@@ -0,0 +1,15 @@
1
+ import { TradeResponseType } from "../../types";
2
+ import { AbastrcatTrade } from "../trade/abstract_trade";
3
+ import { AbstractTransactionResultCheck } from "../trade/abstract_tx_check";
4
+ import { AppConfig } from "./app_config";
5
+ export declare class TradeAppConfig extends AppConfig {
6
+ is_already_subscribe_wallet_raw_txn: boolean;
7
+ trade_instance: AbastrcatTrade;
8
+ tx_result_checker: AbstractTransactionResultCheck;
9
+ constructor();
10
+ init(): Promise<void>;
11
+ init_trade_runtime(): Promise<void>;
12
+ subscribe_order_event(trade_instance: AbastrcatTrade, tx_result_checker: AbstractTransactionResultCheck): Promise<void>;
13
+ subscribe_wallet_raw_txn_event(): void;
14
+ cache_trade_result(trade_response: TradeResponseType): Promise<void>;
15
+ }
@@ -0,0 +1,68 @@
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.TradeAppConfig = void 0;
13
+ const __1 = require("..");
14
+ const handle_order_message_1 = require("../trade/handle_order_message");
15
+ const app_config_1 = require("./app_config");
16
+ class TradeAppConfig extends app_config_1.AppConfig {
17
+ constructor() {
18
+ super();
19
+ this.is_already_subscribe_wallet_raw_txn = false;
20
+ }
21
+ init() {
22
+ const _super = Object.create(null, {
23
+ init: { get: () => super.init }
24
+ });
25
+ return __awaiter(this, void 0, void 0, function* () {
26
+ yield _super.init.call(this);
27
+ });
28
+ }
29
+ init_trade_runtime() {
30
+ return __awaiter(this, void 0, void 0, function* () {
31
+ try {
32
+ let { chain_id, dex_id, trade_group_id, trade_pair } = this.env_args;
33
+ this.trade_runtime = yield this.arb_cache.create_trade_runtime(chain_id, trade_group_id, dex_id, trade_pair);
34
+ this.trade_runtime.wallet_token_accounts = new Map();
35
+ }
36
+ catch (err) {
37
+ (0, __1.log_error)(`create_trade_runtime error!`, err);
38
+ yield (0, __1.sleep)(1000);
39
+ process.exit(0);
40
+ }
41
+ });
42
+ }
43
+ subscribe_order_event(trade_instance, tx_result_checker) {
44
+ return __awaiter(this, void 0, void 0, function* () {
45
+ let handler = (message) => (0, handle_order_message_1.handle_order_message)(this, trade_instance, tx_result_checker, message);
46
+ let group_id = this.trade_runtime.group.id;
47
+ let pair_name = this.trade_runtime.pair_name;
48
+ let dex_id = this.trade_runtime.dex_id;
49
+ yield this.arb_event_subscriber.subscribe_order_event(group_id, pair_name, dex_id, handler);
50
+ (0, __1.log_info)(`subscribe_order_event, success`, { dex_id, group_id, pair_name });
51
+ });
52
+ }
53
+ subscribe_wallet_raw_txn_event() {
54
+ throw new Error('not implemented');
55
+ }
56
+ cache_trade_result(trade_response) {
57
+ return __awaiter(this, void 0, void 0, function* () {
58
+ try {
59
+ (0, __1.log_info)(`cache_trade_result`, trade_response);
60
+ yield this.arb_cache.cache_trade_result(trade_response);
61
+ }
62
+ catch (err) {
63
+ (0, __1.log_error)(`cache_trade_result error!`, err);
64
+ }
65
+ });
66
+ }
67
+ }
68
+ exports.TradeAppConfig = TradeAppConfig;
@@ -23,5 +23,6 @@ export declare class EnvArgs {
23
23
  trade_pool_address: string;
24
24
  trade_pool_name: string;
25
25
  trade_pool_fee_rate: number;
26
+ cache_price_seconds: number;
26
27
  constructor(chain_id?: CHAIN_ID, dex_id?: DEX_ID);
27
28
  }
@@ -34,6 +34,7 @@ class EnvArgs {
34
34
  this.trade_pool_address = process.env.TRADE_POOL_ADDRESS;
35
35
  this.trade_pool_name = process.env.TRADE_POOL_NAME;
36
36
  this.trade_pool_fee_rate = parseInt(process.env.TRADE_POOL_FEE_RATE || '0');
37
+ this.cache_price_seconds = parseInt(process.env.CACHE_PRICE_SECONDS || '600');
37
38
  (0, __1.log_info)('EnvArgs init finish', this);
38
39
  }
39
40
  }
@@ -1,2 +1,4 @@
1
+ import { AppConfig } from './app_config';
1
2
  export * from './env_args';
2
3
  export * from './app_config';
4
+ export declare const getGlobalAppConfig: () => AppConfig;
@@ -14,5 +14,14 @@ 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
+ exports.getGlobalAppConfig = void 0;
17
18
  __exportStar(require("./env_args"), exports);
18
19
  __exportStar(require("./app_config"), exports);
20
+ const getGlobalAppConfig = () => {
21
+ let app_config = global.app_config;
22
+ if (!app_config) {
23
+ throw new Error('app_config is not set');
24
+ }
25
+ return app_config;
26
+ };
27
+ exports.getGlobalAppConfig = getGlobalAppConfig;
package/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@ export * from './app_config';
8
8
  export * from './pool';
9
9
  export * from './quote';
10
10
  export * from './token';
11
+ export * from './trade';
11
12
  export declare const FAILED = "FAILED";
12
13
  export declare const SUCCESS = "SUCCESS";
13
14
  export declare const NOT_FOUND = "NOT_FOUND";
@@ -76,6 +77,11 @@ export declare enum CACHE_KEY_TYPE {
76
77
  ORDER_MESSAGE = "o:msg",
77
78
  ORDER_RESULT = "o:result"
78
79
  }
80
+ export declare enum LOCAL_EVENT_NAME {
81
+ EVENT_POOL_ACCOUNT_CHANGE = "EVENT_POOL_ACCOUNT_CHANGE",
82
+ EVENT_WALLET_TRANSACTION = "EVENT_WALLET_TRANSACTION",
83
+ EVENT_WALLET_TRANSACTION_NEW_TXID = "EVENT_WALLET_TRANSACTION_NEW_TXID"
84
+ }
79
85
  export declare const format_symbol_name: (symbol: string) => string;
80
86
  export declare const format_unique_orderbook_id: (chain_id: CHAIN_ID, dex_id: DEX_ID, pool_id: string, fee_rate: number) => string;
81
87
  export declare const parse_unique_orderbook_id: (unique_orderbook_id: string) => UniqueOrderbookIdType;
package/dist/index.js CHANGED
@@ -48,8 +48,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
48
48
  return (mod && mod.__esModule) ? mod : { "default": mod };
49
49
  };
50
50
  Object.defineProperty(exports, "__esModule", { value: true });
51
- exports.uuid = exports.DATE_TIME_FORMAT_NO_WHITESPACE = exports.DATE_TIME_FORMAT_DEFAULT = exports.to_json_str = exports.DecimalUtil = exports.generateRandomNumber = exports.LOG = exports._active_log_level = exports.LOG_LEVEL = exports.REDIS_EVENT_TYPE_TRADE_INSTANCE_CHANGE = exports.REDIS_EVENT_TYPE_ORDER = exports.REDIS_EVENT_TYPE_QUOTE = exports.REDIS_EVENT_TYPE_CONFIG_CHANGE = exports.REDIS_EVENT_CHANNEL = exports.get_tx_result_channel_name = exports.get_wallet_raw_tx_channel_name = exports.get_order_channel_name = exports.get_quote_channel_name = exports.get_config_channel_name = exports.get_cache_key = exports.getArbEventSubscriber = exports.getArbEventPublisher = exports.getArbCache = exports.getRedisCommamd = exports.getLoadingCache = exports.getRedisCache = exports.format_order_lock_key = exports.format_unique_order_msg_id = exports.parse_unique_orderbook_id = exports.format_unique_orderbook_id = exports.format_symbol_name = exports.CACHE_KEY_TYPE = exports.OnChainDataSubscribeType = exports.TradeErrorCodeType = exports.SystemErrorCodeType = exports.TRADE_TYPE = exports.GROUP_ID = exports.DEX_ID = exports.CHAIN_ID = exports.STREAMING_TRANSACTION_CONFIRMED = exports.TRANSACTION_STATE_FAILED = exports.TRANSACTION_STATE_SUCCESS = exports.TRANSACTION_STATE_PROCESSING = exports.QUOTE_AMOUNT_USD_MAX = exports.QUOTE_AMOUNT_USD_MIN = exports.REGEX_HEX_PREFIX = exports.PROCESSING = exports.NOT_FOUND = exports.SUCCESS = exports.FAILED = void 0;
52
- exports.execute_bash = exports.inspect_arb_local_cache = exports.save_trade_execution_logs = exports.parse_trade_cmdline_args = exports.get_input_out_token_fix = exports.get_input_out_token = exports.calc_amount_in_token = exports.estimate_amount_in_token = exports.failed = exports.success = exports.home_dir = exports.postJSON = exports.deep_merge_object = exports.isArray = exports.isTrue = exports.deep_clone = void 0;
51
+ exports.DATE_TIME_FORMAT_NO_WHITESPACE = exports.DATE_TIME_FORMAT_DEFAULT = exports.to_json_str = exports.DecimalUtil = exports.generateRandomNumber = exports.LOG = exports._active_log_level = exports.LOG_LEVEL = exports.REDIS_EVENT_TYPE_TRADE_INSTANCE_CHANGE = exports.REDIS_EVENT_TYPE_ORDER = exports.REDIS_EVENT_TYPE_QUOTE = exports.REDIS_EVENT_TYPE_CONFIG_CHANGE = exports.REDIS_EVENT_CHANNEL = exports.get_tx_result_channel_name = exports.get_wallet_raw_tx_channel_name = exports.get_order_channel_name = exports.get_quote_channel_name = exports.get_config_channel_name = exports.get_cache_key = exports.getArbEventSubscriber = exports.getArbEventPublisher = exports.getArbCache = exports.getRedisCommamd = exports.getLoadingCache = exports.getRedisCache = exports.format_order_lock_key = exports.format_unique_order_msg_id = exports.parse_unique_orderbook_id = exports.format_unique_orderbook_id = exports.format_symbol_name = exports.LOCAL_EVENT_NAME = exports.CACHE_KEY_TYPE = exports.OnChainDataSubscribeType = exports.TradeErrorCodeType = exports.SystemErrorCodeType = exports.TRADE_TYPE = exports.GROUP_ID = exports.DEX_ID = exports.CHAIN_ID = exports.STREAMING_TRANSACTION_CONFIRMED = exports.TRANSACTION_STATE_FAILED = exports.TRANSACTION_STATE_SUCCESS = exports.TRANSACTION_STATE_PROCESSING = exports.QUOTE_AMOUNT_USD_MAX = exports.QUOTE_AMOUNT_USD_MIN = exports.REGEX_HEX_PREFIX = exports.PROCESSING = exports.NOT_FOUND = exports.SUCCESS = exports.FAILED = void 0;
52
+ exports.execute_bash = exports.inspect_arb_local_cache = exports.save_trade_execution_logs = exports.parse_trade_cmdline_args = exports.get_input_out_token_fix = exports.get_input_out_token = exports.calc_amount_in_token = exports.estimate_amount_in_token = exports.failed = exports.success = exports.home_dir = exports.postJSON = exports.deep_merge_object = exports.isArray = exports.isTrue = exports.deep_clone = exports.uuid = void 0;
53
53
  exports._caller = _caller;
54
54
  exports.log_trace = log_trace;
55
55
  exports.log_debug = log_debug;
@@ -87,6 +87,7 @@ __exportStar(require("./app_config"), exports);
87
87
  __exportStar(require("./pool"), exports);
88
88
  __exportStar(require("./quote"), exports);
89
89
  __exportStar(require("./token"), exports);
90
+ __exportStar(require("./trade"), exports);
90
91
  const short = require('short-uuid');
91
92
  const exec = require('util').promisify(require('child_process').exec);
92
93
  exports.FAILED = 'FAILED';
@@ -165,6 +166,12 @@ var CACHE_KEY_TYPE;
165
166
  CACHE_KEY_TYPE["ORDER_MESSAGE"] = "o:msg";
166
167
  CACHE_KEY_TYPE["ORDER_RESULT"] = "o:result";
167
168
  })(CACHE_KEY_TYPE || (exports.CACHE_KEY_TYPE = CACHE_KEY_TYPE = {}));
169
+ var LOCAL_EVENT_NAME;
170
+ (function (LOCAL_EVENT_NAME) {
171
+ LOCAL_EVENT_NAME["EVENT_POOL_ACCOUNT_CHANGE"] = "EVENT_POOL_ACCOUNT_CHANGE";
172
+ LOCAL_EVENT_NAME["EVENT_WALLET_TRANSACTION"] = "EVENT_WALLET_TRANSACTION";
173
+ LOCAL_EVENT_NAME["EVENT_WALLET_TRANSACTION_NEW_TXID"] = "EVENT_WALLET_TRANSACTION_NEW_TXID";
174
+ })(LOCAL_EVENT_NAME || (exports.LOCAL_EVENT_NAME = LOCAL_EVENT_NAME = {}));
168
175
  const format_symbol_name = (symbol) => {
169
176
  return symbol.replace('USDC', 'USDT')
170
177
  .replace('WTRX', 'TRX')
@@ -0,0 +1,3 @@
1
+ import { FormattedTokenPrice } from "../..";
2
+ export declare const fetchPriceFromCache: (token_address_list: string[]) => Promise<Map<string, FormattedTokenPrice>>;
3
+ export declare function cache_new_market_price(token_address: string, market_price: string, market_source: string): Promise<void>;
@@ -0,0 +1,110 @@
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.fetchPriceFromCache = void 0;
13
+ exports.cache_new_market_price = cache_new_market_price;
14
+ const __1 = require("../..");
15
+ const check_token_price_timeout = (token_info, token_price_timeout_seconds) => {
16
+ if ((0, __1.isEmpty)(token_info.market_price) || (0, __1.isEmpty)(token_info.update_time)) {
17
+ return true;
18
+ }
19
+ let last_update_time = token_info.update_time;
20
+ let diff_seconds = Math.floor((Date.now() - (0, __1.parseDateTimeStrToMills)(last_update_time)) / 1000);
21
+ return diff_seconds > token_price_timeout_seconds;
22
+ };
23
+ const fetchPriceFromCache = (token_address_list) => __awaiter(void 0, void 0, void 0, function* () {
24
+ let result = new Map();
25
+ let global_app_config;
26
+ try {
27
+ global_app_config = (0, __1.getGlobalAppConfig)();
28
+ }
29
+ catch (err) {
30
+ (0, __1.log_warn)('global_app_config is not set, skip get token price from cache');
31
+ return result;
32
+ }
33
+ let token_price_timeout_seconds = 600;
34
+ let all_token_list = yield global_app_config.arb_cache.get_token_list();
35
+ let token_list = all_token_list.filter(e => token_address_list.includes(e.address) && !(0, __1.isEmpty)(e.market_price) && !(0, __1.isEmpty)(e.update_time));
36
+ let not_found_token_list = [];
37
+ for (let token_info of token_list) {
38
+ try {
39
+ if (check_token_price_timeout(token_info, token_price_timeout_seconds)) {
40
+ not_found_token_list.push(token_info);
41
+ }
42
+ else {
43
+ let diff_seconds = Math.floor((Date.now() - (0, __1.parseDateTimeStrToMills)(token_info.update_time)) / 1000);
44
+ result.set(token_info.address, {
45
+ address: token_info.address,
46
+ price: token_info.market_price,
47
+ update_time: token_info.update_time,
48
+ });
49
+ (0, __1.log_info)(`get token price from cache success: ${token_info.symbol} ${token_info.address}, price=${token_info.market_price} (${diff_seconds}s ago)`);
50
+ }
51
+ }
52
+ catch (err) {
53
+ (0, __1.log_error)(`get token price from cache failed`, err);
54
+ }
55
+ }
56
+ for (let token_info of not_found_token_list) {
57
+ let price_info = yield global_app_config.get_token_market_price(token_info.symbol);
58
+ if (!price_info || check_token_price_timeout(price_info, token_price_timeout_seconds)) {
59
+ continue;
60
+ }
61
+ result.set(token_info.address, {
62
+ address: token_info.address,
63
+ price: price_info.market_price,
64
+ update_time: price_info.update_time,
65
+ });
66
+ }
67
+ return result;
68
+ });
69
+ exports.fetchPriceFromCache = fetchPriceFromCache;
70
+ function cache_new_market_price(token_address, market_price, market_source) {
71
+ return __awaiter(this, void 0, void 0, function* () {
72
+ let global_app_config;
73
+ try {
74
+ global_app_config = (0, __1.getGlobalAppConfig)();
75
+ }
76
+ catch (err) {
77
+ (0, __1.log_warn)('global_app_config is not set, skip get token price from cache');
78
+ return;
79
+ }
80
+ let ttl = global_app_config.env_args.cache_price_seconds || 900;
81
+ let tokenInfo = global_app_config.arb_cache.token_address_map.get(token_address);
82
+ if (!tokenInfo) {
83
+ tokenInfo = (yield global_app_config.arb_cache.get_token_list_no_cache()).find(e => e.address === token_address);
84
+ }
85
+ if (!tokenInfo) {
86
+ (0, __1.log_warn)(`tokenInfo is not found in cache: token_address=${token_address}`);
87
+ return;
88
+ }
89
+ let { symbol, address } = tokenInfo;
90
+ if (market_price && Number(market_price) > 0) {
91
+ let clone_token_info = (0, __1.deep_clone)(tokenInfo);
92
+ clone_token_info.market_price = market_price;
93
+ global_app_config.cache_token_market_price(clone_token_info, ttl)
94
+ .then(() => {
95
+ (0, __1.log_info)(`cache new market price success: ${symbol} ${address}, price=${market_price} (${ttl}s), source=${market_source}`);
96
+ })
97
+ .catch(err => {
98
+ (0, __1.log_error)(`cache new market price failed: ${symbol} ${address}, price=${market_price} (${ttl}s)`, err);
99
+ });
100
+ }
101
+ else {
102
+ (0, __1.log_warn)(`skip cache invalid market_price from ${market_source}`, {
103
+ symbol,
104
+ address,
105
+ market_price,
106
+ market_source,
107
+ });
108
+ }
109
+ });
110
+ }
@@ -17,11 +17,18 @@ require('dotenv').config();
17
17
  const axios_1 = __importDefault(require("axios"));
18
18
  const index_1 = require("../../index");
19
19
  const gecko_terminal_1 = require("./gecko_terminal");
20
+ const cached_price_1 = require("./cached_price");
20
21
  function get_bsc_token_price_info(addresses) {
21
22
  return __awaiter(this, void 0, void 0, function* () {
22
23
  addresses = addresses.map(addr => addr.toLowerCase());
23
24
  const result = new Map();
24
25
  const PRICE_CHANNELS = [
26
+ {
27
+ name: 'CachedPrice',
28
+ fetchFn: cached_price_1.fetchPriceFromCache,
29
+ batchSize: 100,
30
+ batchDelay: 1000,
31
+ },
25
32
  {
26
33
  name: 'PancakeSwap',
27
34
  fetchFn: fetchPriceFromPancakeSwap,
@@ -53,8 +60,10 @@ function get_bsc_token_price_info(addresses) {
53
60
  for (const [address, priceInfo] of channelResult.entries()) {
54
61
  result.set(address, priceInfo);
55
62
  remainingAddresses = remainingAddresses.filter(addr => addr !== address);
63
+ if (channel.name !== 'CachedPrice') {
64
+ (0, cached_price_1.cache_new_market_price)(address, priceInfo.price, channel.name);
65
+ }
56
66
  }
57
- (0, index_1.log_debug)(`[get_token_price_info] ${channel.name} found prices for ${channelResult.size}/${batch.length} tokens in batch ${i + 1}`);
58
67
  }
59
68
  catch (error) {
60
69
  (0, index_1.log_warn)(`[get_token_price_info] Error processing batch ${i + 1} with ${channel.name}: ${error instanceof Error ? error.message : String(error)}`);
@@ -17,10 +17,17 @@ require('dotenv').config();
17
17
  const axios_1 = __importDefault(require("axios"));
18
18
  const index_1 = require("../../index");
19
19
  const gecko_terminal_1 = require("./gecko_terminal");
20
+ const cached_price_1 = require("./cached_price");
20
21
  function get_solana_token_price_info(addresses) {
21
22
  return __awaiter(this, void 0, void 0, function* () {
22
23
  const result = new Map();
23
24
  const PRICE_CHANNELS = [
25
+ {
26
+ name: 'CachedPrice',
27
+ fetchFn: cached_price_1.fetchPriceFromCache,
28
+ batchSize: 100,
29
+ batchDelay: 1000,
30
+ },
24
31
  {
25
32
  name: 'Jupiter',
26
33
  fetchFn: fetchPriceFromJupiter,
@@ -52,6 +59,9 @@ function get_solana_token_price_info(addresses) {
52
59
  for (const [address, priceInfo] of channelResult.entries()) {
53
60
  result.set(address, priceInfo);
54
61
  remainingAddresses = remainingAddresses.filter(addr => addr !== address);
62
+ if (channel.name !== 'CachedPrice') {
63
+ (0, cached_price_1.cache_new_market_price)(address, priceInfo.price, channel.name);
64
+ }
55
65
  }
56
66
  (0, index_1.log_debug)(`[get_token_price_info] ${channel.name} found prices for ${channelResult.size}/${batch.length} tokens in batch ${i + 1}`);
57
67
  }
@@ -17,10 +17,17 @@ require('dotenv').config();
17
17
  const axios_1 = __importDefault(require("axios"));
18
18
  const index_1 = require("../../index");
19
19
  const gecko_terminal_1 = require("./gecko_terminal");
20
+ const cached_price_1 = require("./cached_price");
20
21
  function get_tron_token_price_info(addresses) {
21
22
  return __awaiter(this, void 0, void 0, function* () {
22
23
  const result = new Map();
23
24
  const PRICE_CHANNELS = [
25
+ {
26
+ name: 'CachedPrice',
27
+ fetchFn: cached_price_1.fetchPriceFromCache,
28
+ batchSize: 100,
29
+ batchDelay: 1000,
30
+ },
24
31
  {
25
32
  name: 'TronscanALL',
26
33
  fetchFn: fetchPriceFromTronscanALL,
@@ -58,6 +65,9 @@ function get_tron_token_price_info(addresses) {
58
65
  for (const [address, priceInfo] of channelResult.entries()) {
59
66
  result.set(address, priceInfo);
60
67
  remainingAddresses = remainingAddresses.filter(addr => addr !== address);
68
+ if (channel.name !== 'CachedPrice') {
69
+ (0, cached_price_1.cache_new_market_price)(address, priceInfo.price, channel.name);
70
+ }
61
71
  }
62
72
  (0, index_1.log_debug)(`[get_token_price_info] ${channel.name} found prices for ${channelResult.size}/${batch.length} tokens in batch ${i + 1}`);
63
73
  }
@@ -0,0 +1,5 @@
1
+ import { TradeContext } from "./trade_context";
2
+ export declare abstract class AbastrcatTrade {
3
+ abstract init(): void;
4
+ abstract execute(context: TradeContext): Promise<string>;
5
+ }
@@ -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,25 @@
1
+ import { EventEmitter } from 'events';
2
+ import { EnvArgs } from "..";
3
+ import { OrderMessageType, PriceMessageType, StandardPoolInfoType, StandardSwapDetailType, TradeResultType } from "../../types";
4
+ import { TradeContext } from "./trade_context";
5
+ export declare abstract class AbstractTransactionResultCheck {
6
+ env_args: EnvArgs;
7
+ event_emitter: EventEmitter;
8
+ wallet: string;
9
+ context: TradeContext;
10
+ group_id: string;
11
+ txid: string;
12
+ trace_id: string;
13
+ price_msg: PriceMessageType;
14
+ order_msg: OrderMessageType;
15
+ pool_info: StandardPoolInfoType;
16
+ intervalId: any;
17
+ check_count: number;
18
+ trade_result_already_processed: boolean;
19
+ constructor(env_args: EnvArgs, event_emitter: EventEmitter, context: TradeContext, txid: string);
20
+ init_tx_status(): this;
21
+ check(): Promise<void>;
22
+ abstract check_tx_result_interval(): void;
23
+ abstract on_subscibe_transaction(): void;
24
+ map_swap_result_to_tx_result(swap_result: StandardSwapDetailType): TradeResultType;
25
+ }
@@ -0,0 +1,131 @@
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.AbstractTransactionResultCheck = void 0;
13
+ const __1 = require("..");
14
+ class AbstractTransactionResultCheck {
15
+ constructor(env_args, event_emitter, context, txid) {
16
+ this.env_args = env_args;
17
+ this.event_emitter = event_emitter;
18
+ this.context = context;
19
+ this.group_id = context.group_id;
20
+ this.wallet = context.trade_runtime.wallet.public_key;
21
+ this.txid = txid;
22
+ this.price_msg = context.price_msg;
23
+ this.order_msg = context.order_msg;
24
+ this.pool_info = context.pool_info;
25
+ this.trace_id = context.order_msg.order_trace_id;
26
+ this.check_count = 0;
27
+ this.trade_result_already_processed = false;
28
+ }
29
+ init_tx_status() {
30
+ let empty_trade_result = JSON.parse(JSON.stringify({
31
+ group_id: this.context.group_id,
32
+ txid: this.txid
33
+ }));
34
+ this.event_emitter.emit(__1.TRANSACTION_STATE_PROCESSING, empty_trade_result);
35
+ return this;
36
+ }
37
+ check() {
38
+ return __awaiter(this, void 0, void 0, function* () {
39
+ this.check_tx_result_interval();
40
+ this.on_subscibe_transaction();
41
+ });
42
+ }
43
+ map_swap_result_to_tx_result(swap_result) {
44
+ let { success, error_code, wallet, block_number, block_time: order_block_time, txid, tx_price, tokenA, tokenB, gas_fee } = swap_result;
45
+ let { pool_name, is_reverse_token } = this.pool_info;
46
+ let { chain_id, dex_id, unique_orderbook_id, pair, price_id, time: quote_time, ask, bid } = this.price_msg;
47
+ let { group_id, unique_order_msg_id, order_send_time, order_recv_time, order_submit_time, aToB } = this.order_msg;
48
+ let order_price = aToB ? bid.price : ask.price;
49
+ let server_info = (0, __1.getServerInfo)();
50
+ let order_end_time = Date.now();
51
+ let start_time = order_recv_time;
52
+ let end_time = order_end_time;
53
+ let total_time = end_time - start_time;
54
+ let total_order_time = total_time;
55
+ let time = {
56
+ block_time: quote_time.block_time,
57
+ stream_time: quote_time.stream_time,
58
+ quote_start_time: quote_time.quote_start_time,
59
+ quote_end_time: quote_time.quote_end_time,
60
+ price_time: quote_time.price_time,
61
+ total_quote_time: quote_time.total_quote_time,
62
+ order_send_time,
63
+ order_recv_time,
64
+ order_submit_time,
65
+ order_block_time,
66
+ order_end_time,
67
+ total_order_time,
68
+ };
69
+ let broadcast = [];
70
+ broadcast.push({
71
+ rpc: {
72
+ read: 'qn',
73
+ write: 'qn'
74
+ },
75
+ type: 'mainnet',
76
+ fee: gas_fee
77
+ });
78
+ let trade_balance_change = {
79
+ tokenA: {
80
+ symbol: tokenA.symbol,
81
+ address: tokenA.address,
82
+ pre_bal: tokenA.pre_bal,
83
+ post_bal: tokenA.post_bal,
84
+ change: Number(tokenA.change),
85
+ decimals: tokenA.decimals,
86
+ },
87
+ tokenB: {
88
+ symbol: tokenB.symbol,
89
+ address: tokenB.address,
90
+ pre_bal: tokenB.pre_bal,
91
+ post_bal: tokenB.post_bal,
92
+ change: Number(tokenB.change),
93
+ decimals: tokenB.decimals,
94
+ },
95
+ };
96
+ if (is_reverse_token) {
97
+ let { tokenA, tokenB } = trade_balance_change;
98
+ trade_balance_change.tokenA = tokenB;
99
+ trade_balance_change.tokenB = tokenA;
100
+ }
101
+ let trade_extra_info = {
102
+ time,
103
+ broadcast,
104
+ server_info,
105
+ };
106
+ const c_id = this.order_msg.c_id || '';
107
+ const trade_result = {
108
+ success,
109
+ error_code,
110
+ start_time,
111
+ end_time,
112
+ total_time,
113
+ group_id,
114
+ wallet,
115
+ chain_id,
116
+ pair,
117
+ dex_id,
118
+ txid,
119
+ unique_orderbook_id,
120
+ unique_order_msg_id,
121
+ order_price,
122
+ aToB,
123
+ tx_price,
124
+ balance: trade_balance_change,
125
+ execution: trade_extra_info,
126
+ c_id
127
+ };
128
+ return trade_result;
129
+ }
130
+ }
131
+ exports.AbstractTransactionResultCheck = AbstractTransactionResultCheck;
@@ -0,0 +1,6 @@
1
+ import { AppConfig } from "../app_config";
2
+ import { TradeAppConfig } from "../app_config/app_trade_config";
3
+ import { AbastrcatTrade } from "./abstract_trade";
4
+ import { AbstractTransactionResultCheck } from "./abstract_tx_check";
5
+ export declare const try_lock_order_msg: (appConfig: AppConfig, order_msg: any) => Promise<boolean>;
6
+ export declare const handle_order_message: (trade_appconfig: TradeAppConfig, trade_instance: AbastrcatTrade, tx_result_checker: AbstractTransactionResultCheck, recv_order_msg: string) => Promise<void>;
@@ -0,0 +1,117 @@
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.handle_order_message = exports.try_lock_order_msg = void 0;
13
+ const __1 = require("..");
14
+ const trade_context_1 = require("./trade_context");
15
+ const check_parse_order_msg = (appConfig, order_msg) => __awaiter(void 0, void 0, void 0, function* () {
16
+ let { unique_orderbook_id, price_id, group_id, unique_order_msg_id } = order_msg;
17
+ const runtime_group_id = appConfig.trade_runtime.group.id;
18
+ if (group_id !== runtime_group_id) {
19
+ throw new Error(`group_id not match!!! ${(0, __1.to_json_str)({ group_id, runtime_group_id })}`);
20
+ }
21
+ if ((0, __1.isEmpty)(unique_order_msg_id)) {
22
+ throw new Error(`unique_order_msg_id is empty or null! unique_order_msg_id=${unique_order_msg_id}`);
23
+ }
24
+ let price_msg = yield appConfig.arb_cache.get_price_message(price_id);
25
+ if ((0, __1.isEmpty)(price_msg)) {
26
+ throw new Error(`price_msg not found in the cache! price_id=${price_id}`);
27
+ }
28
+ let id_parts = (0, __1.parse_unique_orderbook_id)(unique_orderbook_id);
29
+ if (id_parts.dex_id != price_msg.dex_id ||
30
+ id_parts.pool_id != price_msg.pool_id) {
31
+ (0, __1.log_warn)(`check data: order_msg VS price_msg, not match!!!`, {
32
+ order_msg,
33
+ uinique_orderbook: id_parts,
34
+ price_msg,
35
+ });
36
+ }
37
+ return {
38
+ price_msg,
39
+ id_parts
40
+ };
41
+ });
42
+ const try_lock_order_msg = (appConfig, order_msg) => __awaiter(void 0, void 0, void 0, function* () {
43
+ let { chain_id, group_id, price_id, order_trace_id } = order_msg;
44
+ let lock_order_key = (0, __1.format_order_lock_key)(chain_id, group_id, price_id, order_trace_id);
45
+ (0, __1.log_info)(`try_lock_order_msg, key=${lock_order_key}`);
46
+ let is_lock_success = yield appConfig.arb_cache.redis_cmd.set_nx(lock_order_key, '');
47
+ if (is_lock_success) {
48
+ (0, __1.log_info)(`try_lock_order_msg, key=${lock_order_key}, success`);
49
+ appConfig.arb_cache.redis_cmd.expire(lock_order_key, 60)
50
+ .then(res => (0, __1.log_trace)(`expire lock: key=${lock_order_key}, success`))
51
+ .catch(err => (0, __1.log_error)(`expire lock: key=${lock_order_key}, error!`, err));
52
+ }
53
+ else {
54
+ (0, __1.log_info)(`try_lock_order_msg, key=${lock_order_key}, acquire lock failed!`);
55
+ }
56
+ return is_lock_success;
57
+ });
58
+ exports.try_lock_order_msg = try_lock_order_msg;
59
+ const handle_order_message = (trade_appconfig, trade_instance, tx_result_checker, recv_order_msg) => __awaiter(void 0, void 0, void 0, function* () {
60
+ (0, __1.new_line)(3);
61
+ console.log(`=================================================================================`);
62
+ console.log(`| NEW ORDER MESSAGE |`);
63
+ console.log(`=================================================================================`);
64
+ (0, __1.log_info)(`handle_order_message, on message: `, recv_order_msg);
65
+ let order_event_message = JSON.parse(recv_order_msg);
66
+ if (__1.LOG.debug) {
67
+ (0, __1.log_debug)(`order_event_msg`, order_event_message);
68
+ }
69
+ let { event_time, event_type, group_id, data: order_msg } = order_event_message;
70
+ let { price_msg, id_parts } = yield check_parse_order_msg(trade_appconfig, order_msg);
71
+ let { order_trace_id } = order_msg;
72
+ let { chain_id, dex_id, pool_id, fee_rate } = id_parts;
73
+ if (process.env.ENABLE_MULTIPLE_PROCESS === 'true') {
74
+ let lock_order = yield (0, exports.try_lock_order_msg)(trade_appconfig, order_msg);
75
+ if (!lock_order) {
76
+ (0, __1.log_warn)(`try lock order failed!`, {
77
+ chain_id, group_id, order_trace_id
78
+ });
79
+ return;
80
+ }
81
+ }
82
+ let context;
83
+ let txid = '';
84
+ let order_submit_result;
85
+ try {
86
+ context = new trade_context_1.TradeContext(price_msg, order_msg);
87
+ let { env_args } = trade_appconfig;
88
+ yield context.init(trade_appconfig);
89
+ txid = yield trade_instance.execute(context);
90
+ order_msg.order_submit_time = Date.now();
91
+ order_submit_result = {
92
+ success: true,
93
+ msg: 'SUCCESS',
94
+ txid
95
+ };
96
+ global.event_emitter = trade_appconfig;
97
+ tx_result_checker.init_tx_status().check();
98
+ trade_appconfig.subscribe_wallet_raw_txn_event();
99
+ }
100
+ catch (err) {
101
+ (0, __1.log_error)(`handle_order_message error!`, err);
102
+ order_submit_result = {
103
+ success: false,
104
+ msg: (err === null || err === void 0 ? void 0 : err.message) || 'FAILED',
105
+ txid
106
+ };
107
+ }
108
+ finally {
109
+ trade_appconfig.arb_cache.cache_order_message(Object.assign(Object.assign({}, order_msg), { order_submit_result })).then(res => {
110
+ (0, __1.log_info)(`cache order submit result, success`, { order_msg, order_submit_result, res });
111
+ }).catch(err => {
112
+ (0, __1.log_warn)('cache order submit result, error!', { order_msg, order_submit_result, err });
113
+ console.log(err);
114
+ });
115
+ }
116
+ });
117
+ exports.handle_order_message = handle_order_message;
@@ -0,0 +1,4 @@
1
+ export * from './abstract_trade';
2
+ export * from './abstract_tx_check';
3
+ export * from './trade_context';
4
+ export * from './handle_order_message';
@@ -0,0 +1,20 @@
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("./abstract_tx_check"), exports);
19
+ __exportStar(require("./trade_context"), exports);
20
+ __exportStar(require("./handle_order_message"), exports);
@@ -0,0 +1,20 @@
1
+ import { AppConfig, DEX_ID } from "..";
2
+ import { CHAIN_ID } from "..";
3
+ import { OrderMessageType, PriceMessageType, StandardPoolInfoType } from "../../types";
4
+ import { TradeRuntimeType } from "../../types";
5
+ export declare class TradeContext {
6
+ trade_runtime: TradeRuntimeType;
7
+ price_msg: PriceMessageType;
8
+ order_msg: OrderMessageType;
9
+ order_trace_id: string;
10
+ group_id: string;
11
+ chain_id: CHAIN_ID;
12
+ dex_id: DEX_ID;
13
+ pool_id: string;
14
+ fee_rate: string;
15
+ pool_info: StandardPoolInfoType;
16
+ aToB: boolean;
17
+ slippage_bps: number;
18
+ constructor(price_msg: PriceMessageType, order_msg: OrderMessageType);
19
+ init(appConfig: AppConfig): Promise<void>;
20
+ }
@@ -0,0 +1,49 @@
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 __1 = require("..");
14
+ const __2 = require("..");
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(appConfig) {
22
+ return __awaiter(this, void 0, void 0, function* () {
23
+ this.trade_runtime = appConfig.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, __1.parse_unique_orderbook_id)(unique_orderbook_id);
27
+ this.chain_id = __2.CHAIN_ID[unique_orderbook_id_obj.chain_id];
28
+ this.dex_id = __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 = yield appConfig.arb_cache.get_one_pool_info(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
+ let { inputToken, outputToken } = (0, __1.get_input_out_token)(this.pool_info, this.order_msg.aToB);
36
+ let { amount } = this.order_msg;
37
+ let amount_dot_index = amount.indexOf('.');
38
+ if (amount_dot_index != -1) {
39
+ let amount_with_exact_decimals = amount.substring(0, amount_dot_index + inputToken.decimals + 1);
40
+ let uiAmount = parseFloat(amount_with_exact_decimals).toString();
41
+ this.order_msg.amount = uiAmount;
42
+ (0, __1.log_warn)(`Fix input token's amount decimal: from ${amount} to ${uiAmount}`);
43
+ }
44
+ this.slippage_bps = Math.min(300, Math.max(0, this.trade_runtime.settings.slippage_bps));
45
+ this.aToB = this.pool_info.is_reverse_token ? !this.order_msg.aToB : this.order_msg.aToB;
46
+ });
47
+ }
48
+ }
49
+ exports.TradeContext = TradeContext;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clonegod/ttd-core",
3
- "version": "2.0.7",
3
+ "version": "2.0.9",
4
4
  "description": "Common types and utilities for trading systems - use `npm run push` to publish",
5
5
  "main": "dist/index.js",
6
6
  "types": "types/index.d.ts",