@clonegod/ttd-core 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/analyze/index.d.ts +3 -0
- package/dist/analyze/index.js +49 -0
- package/dist/app_config/app_config.d.ts +15 -0
- package/dist/app_config/app_config.js +50 -0
- package/dist/app_config/env_args.d.ts +16 -0
- package/dist/app_config/env_args.js +28 -0
- package/dist/app_config/index.d.ts +2 -0
- package/dist/app_config/index.js +18 -0
- package/dist/cache/arb_cache.d.ts +80 -0
- package/dist/cache/arb_cache.js +1010 -0
- package/dist/cache/arb_event_pub.d.ts +14 -0
- package/dist/cache/arb_event_pub.js +77 -0
- package/dist/cache/arb_event_sub.d.ts +17 -0
- package/dist/cache/arb_event_sub.js +166 -0
- package/dist/cache/index.d.ts +6 -0
- package/dist/cache/index.js +22 -0
- package/dist/cache/loading_cache.d.ts +62 -0
- package/dist/cache/loading_cache.js +233 -0
- package/dist/cache/redis_client.d.ts +3 -0
- package/dist/cache/redis_client.js +73 -0
- package/dist/cache/redis_cmd.d.ts +14 -0
- package/dist/cache/redis_cmd.js +83 -0
- package/dist/index.d.ts +216 -0
- package/dist/index.js +883 -0
- package/dist/market_price/estimate_token_amount.d.ts +4 -0
- package/dist/market_price/estimate_token_amount.js +109 -0
- package/dist/market_price/index.d.ts +1 -0
- package/dist/market_price/index.js +17 -0
- package/dist/pool/cache_pool_config.d.ts +2 -0
- package/dist/pool/cache_pool_config.js +116 -0
- package/dist/pool/index.d.ts +3 -0
- package/dist/pool/index.js +19 -0
- package/dist/pool/pool_util.d.ts +5 -0
- package/dist/pool/pool_util.js +65 -0
- package/dist/pool/types.d.ts +20 -0
- package/dist/pool/types.js +2 -0
- package/dist/quote/index.d.ts +1 -0
- package/dist/quote/index.js +17 -0
- package/dist/quote/log_quote_price.d.ts +2 -0
- package/dist/quote/log_quote_price.js +29 -0
- package/dist/quote/on_quote_response.d.ts +3 -0
- package/dist/quote/on_quote_response.js +28 -0
- package/dist/quote/publish_quote_price.d.ts +3 -0
- package/dist/quote/publish_quote_price.js +19 -0
- package/dist/quote/to_price_message.d.ts +5 -0
- package/dist/quote/to_price_message.js +103 -0
- package/dist/test/test_is_empty.d.ts +1 -0
- package/dist/test/test_is_empty.js +24 -0
- package/dist/test/test_log_level.d.ts +3 -0
- package/dist/test/test_log_level.js +29 -0
- package/dist/test/test_merge_property.d.ts +1 -0
- package/dist/test/test_merge_property.js +21 -0
- package/dist/token/cache_token_config.d.ts +2 -0
- package/dist/token/cache_token_config.js +68 -0
- package/dist/token/fixed_symbol_address.d.ts +2 -0
- package/dist/token/fixed_symbol_address.js +26 -0
- package/dist/token/index.d.ts +6 -0
- package/dist/token/index.js +22 -0
- package/dist/token/is_not_arb_token.d.ts +1 -0
- package/dist/token/is_not_arb_token.js +24 -0
- package/dist/token/price/gecko_terminal.d.ts +2 -0
- package/dist/token/price/gecko_terminal.js +69 -0
- package/dist/token/price/get_bsc_token_price.d.ts +2 -0
- package/dist/token/price/get_bsc_token_price.js +131 -0
- package/dist/token/price/get_solana_token_price.d.ts +2 -0
- package/dist/token/price/get_solana_token_price.js +17 -0
- package/dist/token/price/get_tron_token_price.d.ts +2 -0
- package/dist/token/price/get_tron_token_price.js +17 -0
- package/dist/token/price/index.d.ts +3 -0
- package/dist/token/price/index.js +19 -0
- package/dist/token/token_util.d.ts +3 -0
- package/dist/token/token_util.js +23 -0
- package/dist/token/types.d.ts +29 -0
- package/dist/token/types.js +2 -0
- package/package.json +47 -0
- package/types/index.d.ts +709 -0
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ArbCache, StandardTokenInfoType } from "../../types";
|
|
2
|
+
export declare class EstimateAmountInToken {
|
|
3
|
+
static estimate_amount_in_token(arb_cache: ArbCache, token: StandardTokenInfoType, amount_in_usd: number, query_token_market_price_url?: string): Promise<string>;
|
|
4
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
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.EstimateAmountInToken = void 0;
|
|
13
|
+
const index_1 = require("../index");
|
|
14
|
+
var tmp_token_price_cache = new Map();
|
|
15
|
+
const PRICE_CACHE_EXPIRE_MILLS = 3 * 60 * 1000;
|
|
16
|
+
setInterval(() => {
|
|
17
|
+
let expires = [];
|
|
18
|
+
let cur_time = new Date().getTime();
|
|
19
|
+
for (let [symbol, value] of tmp_token_price_cache) {
|
|
20
|
+
if (cur_time - value.create_time > PRICE_CACHE_EXPIRE_MILLS) {
|
|
21
|
+
expires.push(symbol);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
expires.forEach(key => tmp_token_price_cache.delete(key));
|
|
25
|
+
}, 5000);
|
|
26
|
+
function set_tmp_market_price(token_with_price) {
|
|
27
|
+
if (!token_with_price || (0, index_1.isEmpty)(token_with_price.market_price)) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
let symbol = token_with_price.symbol;
|
|
31
|
+
tmp_token_price_cache.set(symbol, {
|
|
32
|
+
token_with_price,
|
|
33
|
+
create_time: new Date().getTime()
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
class EstimateAmountInToken {
|
|
37
|
+
static estimate_amount_in_token(arb_cache_1, token_1, amount_in_usd_1) {
|
|
38
|
+
return __awaiter(this, arguments, void 0, function* (arb_cache, token, amount_in_usd, query_token_market_price_url = '') {
|
|
39
|
+
if (['USDT', 'USDC'].includes(token.symbol.toUpperCase())) {
|
|
40
|
+
return amount_in_usd + '';
|
|
41
|
+
}
|
|
42
|
+
if (index_1.LOG.debug) {
|
|
43
|
+
(0, index_1.log_debug)('estimate_amount_in_token, start');
|
|
44
|
+
}
|
|
45
|
+
let symbol = (0, index_1.format_symbol_name)(token.symbol);
|
|
46
|
+
let amountInToken;
|
|
47
|
+
let token_info;
|
|
48
|
+
try {
|
|
49
|
+
if (index_1.LOG.debug) {
|
|
50
|
+
(0, index_1.log_debug)(`try-1 get market price from local cache`);
|
|
51
|
+
}
|
|
52
|
+
let tmp_token_price = tmp_token_price_cache.get(symbol);
|
|
53
|
+
if (tmp_token_price) {
|
|
54
|
+
token_info = tmp_token_price.token_with_price;
|
|
55
|
+
if (index_1.LOG.debug) {
|
|
56
|
+
(0, index_1.log_debug)(`try-1 get market price from local cache, success, hit cache!`, {
|
|
57
|
+
symbol, market_price: token_info.market_price
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
if (index_1.LOG.debug) {
|
|
63
|
+
(0, index_1.log_debug)(`try-2 get market price from remote cache`);
|
|
64
|
+
}
|
|
65
|
+
token_info = yield arb_cache.get_token_market_price(symbol);
|
|
66
|
+
set_tmp_market_price(token_info);
|
|
67
|
+
if (index_1.LOG.debug) {
|
|
68
|
+
(0, index_1.log_debug)(`try-2 get market price from remote cache, res=`, token_info);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
let market_price = token_info === null || token_info === void 0 ? void 0 : token_info.market_price;
|
|
72
|
+
if (market_price) {
|
|
73
|
+
let result = (0, index_1.calc_amount_in_token)(amount_in_usd, market_price, token_info);
|
|
74
|
+
amountInToken = result.amount_in_token;
|
|
75
|
+
}
|
|
76
|
+
if (!amountInToken) {
|
|
77
|
+
try {
|
|
78
|
+
let token_price_url = query_token_market_price_url;
|
|
79
|
+
if (!token_price_url) {
|
|
80
|
+
query_token_market_price_url = process.env.TOKEN_MARKET_PRICE_URL;
|
|
81
|
+
}
|
|
82
|
+
let url = `${token_price_url}?symbol=${symbol}&amount_in_usd=${amount_in_usd}`;
|
|
83
|
+
if (index_1.LOG.debug) {
|
|
84
|
+
(0, index_1.log_debug)(`try get market price from config-center, symbol=${symbol}, start`, { url });
|
|
85
|
+
}
|
|
86
|
+
let res = yield (yield fetch(url)).json();
|
|
87
|
+
let price_with_amount = res['data'];
|
|
88
|
+
amountInToken = price_with_amount.amount_in_token;
|
|
89
|
+
set_tmp_market_price(price_with_amount.token_info);
|
|
90
|
+
if (index_1.LOG.debug) {
|
|
91
|
+
(0, index_1.log_debug)(`try get market price from config-center, symbol=${symbol}, res=`, res);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
(0, index_1.log_error)(`estimate_input_ui_amount error!`, err);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return amountInToken.toString();
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
let default_amount_in_token = 1;
|
|
102
|
+
(0, index_1.new_line)(5);
|
|
103
|
+
(0, index_1.log_error)(`estimate_input_ui_amount error! return default amount: ${default_amount_in_token}`, err);
|
|
104
|
+
return default_amount_in_token.toString();
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.EstimateAmountInToken = EstimateAmountInToken;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './estimate_token_amount';
|
|
@@ -0,0 +1,17 @@
|
|
|
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("./estimate_token_amount"), exports);
|
|
@@ -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
|
+
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.cache_pool_config = void 0;
|
|
16
|
+
const axios_1 = __importDefault(require("axios"));
|
|
17
|
+
const index_1 = require("../index");
|
|
18
|
+
const is_not_arb_token_1 = require("../token/is_not_arb_token");
|
|
19
|
+
const cache_pool_config = (chain_id, valid_tokens_map, sol_pools_cache) => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
|
+
(0, index_1.log_info)(`cache_pool_config start`);
|
|
21
|
+
let count = 0;
|
|
22
|
+
let skip_pool_list = [];
|
|
23
|
+
let config_pool_url = `http://${process.env.CONFIG_CENTER_HOST}/${chain_id}/config/pools`;
|
|
24
|
+
for (let [dex_id, pool_list] of sol_pools_cache) {
|
|
25
|
+
let batch_pools = (0, index_1.chunkArray)(pool_list, 10);
|
|
26
|
+
for (let one_pool_list of batch_pools) {
|
|
27
|
+
let valid_pool_list = [];
|
|
28
|
+
for (let pool of one_pool_list) {
|
|
29
|
+
let is_contains_unkown_symbol = !valid_tokens_map.has(pool.tokenA.symbol) || !valid_tokens_map.has(pool.tokenB.symbol);
|
|
30
|
+
if (is_contains_unkown_symbol || (0, is_not_arb_token_1.is_not_arb_token)(pool.pool_name)) {
|
|
31
|
+
skip_pool_list.push(pool);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
let std_pool = {
|
|
35
|
+
program_id: pool.program_id,
|
|
36
|
+
authority: pool.authority,
|
|
37
|
+
subscribe_type: 'grpc',
|
|
38
|
+
pair: pool.pair,
|
|
39
|
+
dex_id: dex_id,
|
|
40
|
+
pool_name: pool.pool_name,
|
|
41
|
+
pool_address: pool.pool_address,
|
|
42
|
+
pool_address_hex: '',
|
|
43
|
+
tokenA: null,
|
|
44
|
+
tokenB: null,
|
|
45
|
+
vaultA: pool.vaultA,
|
|
46
|
+
vaultB: pool.vaultB,
|
|
47
|
+
router_id: null,
|
|
48
|
+
fee_rate: pool.fee_rate_bps,
|
|
49
|
+
quote_token: pool.quote_token,
|
|
50
|
+
quote_amount_usd: parseInt(process.env.QUOTE_AMOUNT_USD || '100'),
|
|
51
|
+
quote_price_decimals: 18,
|
|
52
|
+
is_reverse_token: null,
|
|
53
|
+
cu_limit: get_cu_limit(dex_id),
|
|
54
|
+
tvl: pool.tvl,
|
|
55
|
+
vol_24h: pool.vol_24h,
|
|
56
|
+
update_time: (0, index_1.getCurDateTime)(),
|
|
57
|
+
enable: true,
|
|
58
|
+
};
|
|
59
|
+
valid_pool_list.push(std_pool);
|
|
60
|
+
count = count + 1;
|
|
61
|
+
}
|
|
62
|
+
if (valid_pool_list.length === 0) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
let body = [
|
|
66
|
+
{
|
|
67
|
+
dex_id: dex_id,
|
|
68
|
+
pool_list: valid_pool_list
|
|
69
|
+
}
|
|
70
|
+
];
|
|
71
|
+
const res = (yield axios_1.default.post(config_pool_url, body, {
|
|
72
|
+
headers: { 'Content-Type': 'application/json' }
|
|
73
|
+
})).data;
|
|
74
|
+
(0, index_1.log_trace)('cache_pool_config, res', res);
|
|
75
|
+
yield (0, index_1.sleep)(200);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
(0, index_1.log_info)(`cache_pool_config finished! sync pool count:${count}, skip: ${skip_pool_list.length}`);
|
|
79
|
+
skip_pool_list.sort((a, b) => a.pair.localeCompare(b.pair));
|
|
80
|
+
(0, index_1.writeFile)(`dist/${chain_id.toLowerCase()}_skip_pool_list.json`, JSON.stringify({
|
|
81
|
+
time: (0, index_1.getCurDateTime)(),
|
|
82
|
+
count: skip_pool_list.length,
|
|
83
|
+
data: skip_pool_list
|
|
84
|
+
}, null, 2));
|
|
85
|
+
let notify_config_change_url = `http://${process.env.CONFIG_CENTER_HOST}/${chain_id}/config/change?type=pool`;
|
|
86
|
+
let res = (yield axios_1.default.get(notify_config_change_url)).data;
|
|
87
|
+
(0, index_1.log_info)('fetch dex pools end, notify config change', {
|
|
88
|
+
notify_config_change_url,
|
|
89
|
+
res
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
exports.cache_pool_config = cache_pool_config;
|
|
93
|
+
function get_cu_limit(dex_id) {
|
|
94
|
+
let cu_limit = 200000;
|
|
95
|
+
switch (dex_id) {
|
|
96
|
+
case index_1.DEX_ID.RAYDIUM_AMM:
|
|
97
|
+
cu_limit = 35000;
|
|
98
|
+
break;
|
|
99
|
+
case index_1.DEX_ID.RAYDIUM_CLMM:
|
|
100
|
+
cu_limit = 120000;
|
|
101
|
+
break;
|
|
102
|
+
case index_1.DEX_ID.RAYDIUM_CPMM:
|
|
103
|
+
cu_limit = 48000;
|
|
104
|
+
break;
|
|
105
|
+
case index_1.DEX_ID.ORCA_CLMM:
|
|
106
|
+
cu_limit = 80000;
|
|
107
|
+
break;
|
|
108
|
+
case index_1.DEX_ID.METEORA_DLMM:
|
|
109
|
+
cu_limit = 80000;
|
|
110
|
+
break;
|
|
111
|
+
case index_1.DEX_ID.PUMPFUN_AMM:
|
|
112
|
+
cu_limit = 80000;
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
return cu_limit;
|
|
116
|
+
}
|
|
@@ -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("./types"), exports);
|
|
18
|
+
__exportStar(require("./pool_util"), exports);
|
|
19
|
+
__exportStar(require("./cache_pool_config"), exports);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { FormattedPoolInfo } from "./types";
|
|
2
|
+
export declare function get_pair_name(native_token: string, pool_name: string): string;
|
|
3
|
+
export declare function check_pool_token_address(pool: FormattedPoolInfo): void;
|
|
4
|
+
export declare function get_quote_token(pair: string, pool_name: string): string;
|
|
5
|
+
export declare function valid_fetch_pool_data(formatted_pool: FormattedPoolInfo, min_tvl: number, min_vol: number, native_token: string): void;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.get_pair_name = get_pair_name;
|
|
4
|
+
exports.check_pool_token_address = check_pool_token_address;
|
|
5
|
+
exports.get_quote_token = get_quote_token;
|
|
6
|
+
exports.valid_fetch_pool_data = valid_fetch_pool_data;
|
|
7
|
+
const token_1 = require("../token");
|
|
8
|
+
const token_util_1 = require("../token/token_util");
|
|
9
|
+
function get_pair_name(native_token, pool_name) {
|
|
10
|
+
let arr = pool_name.split('/');
|
|
11
|
+
if (pool_name.includes(native_token) && (pool_name.includes('USDC') || pool_name.includes('USDT'))) {
|
|
12
|
+
if (pool_name.endsWith(native_token)) {
|
|
13
|
+
arr.reverse();
|
|
14
|
+
}
|
|
15
|
+
return arr.join('/').replace('USDC', 'USDT');
|
|
16
|
+
}
|
|
17
|
+
const symbols = pool_name.split('/');
|
|
18
|
+
if (symbols.includes(native_token)) {
|
|
19
|
+
if (symbols[1] !== native_token) {
|
|
20
|
+
arr.reverse();
|
|
21
|
+
}
|
|
22
|
+
return arr.join('/');
|
|
23
|
+
}
|
|
24
|
+
if (symbols.includes('USDC') || symbols.includes('USDT')) {
|
|
25
|
+
if (symbols[1] !== 'USDC' && symbols[1] !== 'USDT') {
|
|
26
|
+
arr.reverse();
|
|
27
|
+
}
|
|
28
|
+
return arr.join('/').replace('USDC', 'USDT');
|
|
29
|
+
}
|
|
30
|
+
return pool_name;
|
|
31
|
+
}
|
|
32
|
+
function check_pool_token_address(pool) {
|
|
33
|
+
let { pool_name, pool_address, tokenA, tokenB } = pool;
|
|
34
|
+
for (let token of [tokenA, tokenB]) {
|
|
35
|
+
let is_fake_token = token_1.fixed_symbol_address.some(e => e.symbol === token.symbol && e.address !== token.address);
|
|
36
|
+
if (is_fake_token) {
|
|
37
|
+
throw new Error(`Invalid token address of ${token.symbol}: ${token.address}, ${pool_name}, ${pool_address}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function get_quote_token(pair, pool_name) {
|
|
42
|
+
let base_token = pair.split('/')[0];
|
|
43
|
+
let quote_token = pair.split('/')[1];
|
|
44
|
+
if (!pool_name.includes(quote_token)) {
|
|
45
|
+
quote_token = pool_name.split('/').find(e => e !== base_token) || '';
|
|
46
|
+
}
|
|
47
|
+
return quote_token;
|
|
48
|
+
}
|
|
49
|
+
function valid_fetch_pool_data(formatted_pool, min_tvl, min_vol, native_token) {
|
|
50
|
+
let { pool_name, pool_address, tokenA, tokenB, tvl, vol_24h } = formatted_pool;
|
|
51
|
+
let symbols = [tokenA.symbol, tokenB.symbol];
|
|
52
|
+
if ((tvl < min_tvl || vol_24h < min_vol)) {
|
|
53
|
+
throw new Error(`pool is too small: ${pool_name}, ${pool_address}, tvl=${tvl}, vol_24h=${vol_24h}`);
|
|
54
|
+
}
|
|
55
|
+
if (!symbols.includes(native_token) && !symbols.includes('USDC') && !symbols.includes('USDT')) {
|
|
56
|
+
throw new Error(`pool don't contains: SOL, USDC, USDT, ${pool_name}, ${pool_address}`);
|
|
57
|
+
}
|
|
58
|
+
if (!(0, token_util_1.is_valid_symbol)(tokenA.symbol)) {
|
|
59
|
+
throw new Error(`pool contains bad symbol: tokenA.symbol=${tokenA.symbol}, ${pool_name}, ${pool_address}`);
|
|
60
|
+
}
|
|
61
|
+
if (!(0, token_util_1.is_valid_symbol)(tokenB.symbol)) {
|
|
62
|
+
throw new Error(`pool contains bad symbol: tokenB.symbol=${tokenB.symbol}, ${pool_name}, ${pool_address}`);
|
|
63
|
+
}
|
|
64
|
+
check_pool_token_address(formatted_pool);
|
|
65
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { FormattedTokenInfo } from "../token/types";
|
|
2
|
+
export interface FormattedPoolInfo {
|
|
3
|
+
pair: string;
|
|
4
|
+
quote_token: string;
|
|
5
|
+
chain_id: string;
|
|
6
|
+
dex_id: string;
|
|
7
|
+
program_id: string;
|
|
8
|
+
pool_name: string;
|
|
9
|
+
pool_type: string;
|
|
10
|
+
pool_address: string;
|
|
11
|
+
tokenA: FormattedTokenInfo;
|
|
12
|
+
tokenB: FormattedTokenInfo;
|
|
13
|
+
fee_rate_bps: number;
|
|
14
|
+
tvl: number;
|
|
15
|
+
vol_24h: number;
|
|
16
|
+
vaultA: string;
|
|
17
|
+
vaultB: string;
|
|
18
|
+
authority: string;
|
|
19
|
+
lookupTableAccount?: string;
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './on_quote_response';
|
|
@@ -0,0 +1,17 @@
|
|
|
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("./on_quote_response"), exports);
|
|
@@ -0,0 +1,29 @@
|
|
|
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.log_quote_price = log_quote_price;
|
|
13
|
+
const __1 = require("..");
|
|
14
|
+
function log_quote_price(event_source, price_message, tx_hash) {
|
|
15
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
16
|
+
const { unique_orderbook_id, pool_name, pair, fee_rate, price_id, quote_amount_usd, ask, bid, time } = price_message;
|
|
17
|
+
let price_time = new Date().getTime();
|
|
18
|
+
let price_time_str = (0, __1.parseToDateTime)(price_time);
|
|
19
|
+
let times = [
|
|
20
|
+
time.quote_start_time - time.stream_time,
|
|
21
|
+
time.quote_end_time - time.quote_start_time,
|
|
22
|
+
time.price_time - time.stream_time,
|
|
23
|
+
];
|
|
24
|
+
if (event_source || tx_hash) {
|
|
25
|
+
console.log(`> [${event_source}] - ${tx_hash}`);
|
|
26
|
+
}
|
|
27
|
+
console.log(price_time_str, ' - ', unique_orderbook_id, ' - ', String(price_id).padEnd(32), ' - ', pool_name.padEnd(12), ' - ', pair.padEnd(12), ' - ', String(quote_amount_usd).padEnd(4), ' - ', String(ask.price).padEnd(8), ' - ', String(bid.price).padEnd(8), ' - ', `${times.join(',')} ms`, '\n');
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { StandardPoolInfoType, QuoteResultType } from "../../types";
|
|
2
|
+
import { AppConfig } from "../app_config";
|
|
3
|
+
export declare function on_quote_respose(appConfig: AppConfig, pool_info: StandardPoolInfoType, quote_amount_usd: number, execution_price: number, stream_time: number, quote_start_time: number, slot_info: string, result: [QuoteResultType, QuoteResultType, number], txid: string): void;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.on_quote_respose = on_quote_respose;
|
|
4
|
+
const analyze_1 = require("../analyze");
|
|
5
|
+
const log_quote_price_1 = require("./log_quote_price");
|
|
6
|
+
const publish_quote_price_1 = require("./publish_quote_price");
|
|
7
|
+
const to_price_message_1 = require("./to_price_message");
|
|
8
|
+
function on_quote_respose(appConfig, pool_info, quote_amount_usd, execution_price, stream_time, quote_start_time, slot_info, result, txid) {
|
|
9
|
+
const quote_end_time = new Date().getTime();
|
|
10
|
+
const quote_ask_price = Number(result[0].price);
|
|
11
|
+
const quote_bid_price = Number(result[1].price);
|
|
12
|
+
const block_time = result[2];
|
|
13
|
+
const price_time = new Date().getTime();
|
|
14
|
+
const time = {
|
|
15
|
+
block_time,
|
|
16
|
+
stream_time,
|
|
17
|
+
quote_start_time,
|
|
18
|
+
quote_end_time,
|
|
19
|
+
price_time,
|
|
20
|
+
total_quote_time: price_time - stream_time
|
|
21
|
+
};
|
|
22
|
+
(0, to_price_message_1.to_price_message)(appConfig, quote_amount_usd, execution_price, quote_ask_price, quote_bid_price, pool_info, time, slot_info)
|
|
23
|
+
.then((price_msg) => {
|
|
24
|
+
(0, publish_quote_price_1.publish_quote_price)(appConfig, price_msg);
|
|
25
|
+
(0, log_quote_price_1.log_quote_price)(slot_info, price_msg, txid);
|
|
26
|
+
(0, analyze_1.report_trade_analyze_data)('PriceMessageType', Object.assign(Object.assign({}, price_msg), { quote_source: { slot: slot_info, block: null, txid } }));
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.publish_quote_price = void 0;
|
|
4
|
+
const __1 = require("..");
|
|
5
|
+
const publish_quote_price = (appConfig, price_msg) => {
|
|
6
|
+
const chain_id = appConfig.env_args.chain_id;
|
|
7
|
+
let price_id = price_msg.price_id;
|
|
8
|
+
let event = {
|
|
9
|
+
event_type: __1.REDIS_EVENT_TYPE_QUOTE.NEW_QUOTE_PRICE,
|
|
10
|
+
event_time: Date.now(),
|
|
11
|
+
chain_id,
|
|
12
|
+
data: price_msg
|
|
13
|
+
};
|
|
14
|
+
appConfig.arb_cache.redis_event_publisher.publish_quote_price_event(chain_id, event);
|
|
15
|
+
appConfig.arb_cache.cache_price_message(price_msg)
|
|
16
|
+
.then(() => (0, __1.log_debug)(`cache price success, price_id=${price_id}`))
|
|
17
|
+
.catch(err => (0, __1.log_error)(`cache price error! price_id=${price_id}`, err));
|
|
18
|
+
};
|
|
19
|
+
exports.publish_quote_price = publish_quote_price;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { StandardPoolInfoType, QuoteTimeInfoType, PriceMessageType } from '../../types';
|
|
2
|
+
import { AppConfig } from '../app_config';
|
|
3
|
+
export declare const get_quote_token_decimals: (pool_info: StandardPoolInfoType) => number;
|
|
4
|
+
export declare function to_price_message(appConfig: AppConfig, quote_amount_usd: number, tx_price: number, quote_ask_price: number, quote_bid_price: number, pool_info: StandardPoolInfoType, time: QuoteTimeInfoType, slot?: string): Promise<PriceMessageType>;
|
|
5
|
+
export declare function normalize_pair_name(priceMessage: PriceMessageType): void;
|
|
@@ -0,0 +1,103 @@
|
|
|
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.get_quote_token_decimals = void 0;
|
|
16
|
+
exports.to_price_message = to_price_message;
|
|
17
|
+
exports.normalize_pair_name = normalize_pair_name;
|
|
18
|
+
const decimal_js_1 = __importDefault(require("decimal.js"));
|
|
19
|
+
const uuid_1 = require("uuid");
|
|
20
|
+
const __1 = require("..");
|
|
21
|
+
const get_quote_token_decimals = (pool_info) => {
|
|
22
|
+
let decimals = 9;
|
|
23
|
+
let { tokenA, tokenB, quote_token } = pool_info;
|
|
24
|
+
if (tokenA.symbol === quote_token) {
|
|
25
|
+
decimals = tokenA.decimals;
|
|
26
|
+
}
|
|
27
|
+
if (tokenB.symbol === quote_token) {
|
|
28
|
+
decimals = tokenB.decimals;
|
|
29
|
+
}
|
|
30
|
+
return decimals;
|
|
31
|
+
};
|
|
32
|
+
exports.get_quote_token_decimals = get_quote_token_decimals;
|
|
33
|
+
function to_price_message(appConfig, quote_amount_usd, tx_price, quote_ask_price, quote_bid_price, pool_info, time, slot) {
|
|
34
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
35
|
+
let { pool_address, tokenA, tokenB } = pool_info;
|
|
36
|
+
let { dex_id, pool_name, fee_rate, is_reverse_token } = yield appConfig.arb_cache.get_one_pool_info(pool_address);
|
|
37
|
+
let _dex_id = dex_id;
|
|
38
|
+
let price_id = (0, uuid_1.v4)().replace(/-/gi, '');
|
|
39
|
+
let chain_id = appConfig.env_args.chain_id;
|
|
40
|
+
let unique_orderbook_id = (0, __1.format_unique_orderbook_id)(chain_id, _dex_id, pool_address, fee_rate);
|
|
41
|
+
time.price_time = new Date().getTime();
|
|
42
|
+
let fee_rate_bps = fee_rate / 100100;
|
|
43
|
+
let ask_price = getAskPrice(new decimal_js_1.default(quote_ask_price), fee_rate_bps * 0);
|
|
44
|
+
let bid_price = getBidPrice(new decimal_js_1.default(quote_bid_price), fee_rate_bps * 0);
|
|
45
|
+
let price_message = {
|
|
46
|
+
chain_id,
|
|
47
|
+
dex_id,
|
|
48
|
+
price_id,
|
|
49
|
+
pool_id: pool_address,
|
|
50
|
+
pool_name,
|
|
51
|
+
fee_rate,
|
|
52
|
+
pair: pool_name,
|
|
53
|
+
unique_orderbook_id,
|
|
54
|
+
is_reverse_token,
|
|
55
|
+
tokenA: {
|
|
56
|
+
symbol: tokenA.symbol,
|
|
57
|
+
address: tokenA.address,
|
|
58
|
+
address_hex: tokenA.address_hex,
|
|
59
|
+
decimals: tokenA.decimals,
|
|
60
|
+
name: tokenA.name,
|
|
61
|
+
enable: true,
|
|
62
|
+
},
|
|
63
|
+
tokenB: {
|
|
64
|
+
symbol: tokenB.symbol,
|
|
65
|
+
address: tokenB.address,
|
|
66
|
+
address_hex: tokenB.address_hex,
|
|
67
|
+
decimals: tokenB.decimals,
|
|
68
|
+
name: tokenB.name,
|
|
69
|
+
enable: true,
|
|
70
|
+
},
|
|
71
|
+
tx_price: tx_price === null || tx_price === void 0 ? void 0 : tx_price.toFixed(12),
|
|
72
|
+
quote_amount_usd,
|
|
73
|
+
ask: {
|
|
74
|
+
price: ask_price,
|
|
75
|
+
quantity: quote_amount_usd
|
|
76
|
+
},
|
|
77
|
+
bid: {
|
|
78
|
+
price: bid_price,
|
|
79
|
+
quantity: quote_amount_usd
|
|
80
|
+
},
|
|
81
|
+
time,
|
|
82
|
+
slot
|
|
83
|
+
};
|
|
84
|
+
normalize_pair_name(price_message);
|
|
85
|
+
return price_message;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
const getAskPrice = (price, feeRate) => {
|
|
89
|
+
return price.mul(1 + feeRate).toFixed(12);
|
|
90
|
+
};
|
|
91
|
+
const getBidPrice = (price, feeRate) => {
|
|
92
|
+
return price.mul(1 - feeRate).toFixed(12);
|
|
93
|
+
};
|
|
94
|
+
function normalize_pair_name(priceMessage) {
|
|
95
|
+
let { pool_name, is_reverse_token } = priceMessage;
|
|
96
|
+
if (is_reverse_token) {
|
|
97
|
+
pool_name = pool_name.split('/')[1] + '/' + pool_name.split('/')[0];
|
|
98
|
+
}
|
|
99
|
+
const dex_pair_names = pool_name.split('/');
|
|
100
|
+
let cex_base_token = (0, __1.format_symbol_name)(dex_pair_names[0]);
|
|
101
|
+
let cex_qutoe_token = (0, __1.format_symbol_name)(dex_pair_names[1]);
|
|
102
|
+
priceMessage.pair = cex_base_token.toUpperCase() + '/' + cex_qutoe_token.toUpperCase();
|
|
103
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const index_1 = require("../index");
|
|
4
|
+
const main = () => {
|
|
5
|
+
let set1 = new Set();
|
|
6
|
+
console.log('isEmpty Set', (0, index_1.isEmpty)(set1), set1);
|
|
7
|
+
let set2 = new Set();
|
|
8
|
+
set2.add(1);
|
|
9
|
+
console.log('isEmpty Set', (0, index_1.isEmpty)(set2), set2);
|
|
10
|
+
console.log('typeof Set: ', typeof set2);
|
|
11
|
+
console.log('keys in Set: ', Object.keys(set2));
|
|
12
|
+
let map1 = new Map();
|
|
13
|
+
console.log('isEmpty Map', (0, index_1.isEmpty)(map1), map1);
|
|
14
|
+
let map2 = new Map();
|
|
15
|
+
map2.set('SUN/TRX', 'xxxxxxxxx');
|
|
16
|
+
console.log('isEmpty Map', (0, index_1.isEmpty)(map2), map2);
|
|
17
|
+
console.log('typeof Map: ', typeof map2);
|
|
18
|
+
console.log('keys in Map: ', Object.keys(map2));
|
|
19
|
+
let arr1 = [];
|
|
20
|
+
let arr2 = [1];
|
|
21
|
+
console.log('isEmpty array', (0, index_1.isEmpty)(arr1), arr1);
|
|
22
|
+
console.log('isEmpty array', (0, index_1.isEmpty)(arr2), arr2);
|
|
23
|
+
};
|
|
24
|
+
main();
|