@clonegod/ttd-sui-common 1.0.34 → 1.0.36
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/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/trade/abstract_sui_dex_trade_plus.d.ts +32 -0
- package/dist/trade/abstract_sui_dex_trade_plus.js +216 -0
- package/dist/trade/index.d.ts +1 -0
- package/dist/trade/index.js +1 -0
- package/dist/ttd-sui-common/src/constants/index.d.ts +4 -0
- package/dist/ttd-sui-common/src/constants/index.js +8 -0
- package/dist/ttd-sui-common/src/grpc/gas-price-cache.d.ts +21 -0
- package/dist/ttd-sui-common/src/grpc/gas-price-cache.js +83 -0
- package/dist/ttd-sui-common/src/grpc/grpc-connection.d.ts +13 -0
- package/dist/ttd-sui-common/src/grpc/grpc-connection.js +99 -0
- package/dist/ttd-sui-common/src/grpc/index.d.ts +7 -0
- package/dist/ttd-sui-common/src/grpc/index.js +17 -0
- package/dist/ttd-sui-common/src/grpc/ledger-service.d.ts +12 -0
- package/dist/ttd-sui-common/src/grpc/ledger-service.js +161 -0
- package/dist/ttd-sui-common/src/grpc/live-data-service.d.ts +10 -0
- package/dist/ttd-sui-common/src/grpc/live-data-service.js +107 -0
- package/dist/ttd-sui-common/src/grpc/subscription-service.d.ts +7 -0
- package/dist/ttd-sui-common/src/grpc/subscription-service.js +69 -0
- package/dist/ttd-sui-common/src/grpc/sui-grpc-client.d.ts +16 -0
- package/dist/ttd-sui-common/src/grpc/sui-grpc-client.js +38 -0
- package/dist/ttd-sui-common/src/grpc/transaction-service.d.ts +7 -0
- package/dist/ttd-sui-common/src/grpc/transaction-service.js +49 -0
- package/dist/ttd-sui-common/src/index.d.ts +9 -0
- package/dist/ttd-sui-common/src/index.js +25 -0
- package/dist/ttd-sui-common/src/quote/index.d.ts +1 -0
- package/dist/ttd-sui-common/src/quote/index.js +17 -0
- package/dist/ttd-sui-common/src/quote/pricing/index.d.ts +1 -0
- package/dist/ttd-sui-common/src/quote/pricing/index.js +17 -0
- package/dist/ttd-sui-common/src/quote/pricing/token_price_cache.d.ts +9 -0
- package/dist/ttd-sui-common/src/quote/pricing/token_price_cache.js +42 -0
- package/dist/ttd-sui-common/src/redis/index.d.ts +1 -0
- package/dist/ttd-sui-common/src/redis/index.js +17 -0
- package/dist/ttd-sui-common/src/redis/redis_client.d.ts +21 -0
- package/dist/ttd-sui-common/src/redis/redis_client.js +155 -0
- package/dist/ttd-sui-common/src/test/test.d.ts +1 -0
- package/dist/ttd-sui-common/src/test/test.js +126 -0
- package/dist/ttd-sui-common/src/test/test_checkpoint.d.ts +1 -0
- package/dist/ttd-sui-common/src/test/test_checkpoint.js +64 -0
- package/dist/ttd-sui-common/src/test/test_grpc.d.ts +1 -0
- package/dist/ttd-sui-common/src/test/test_grpc.js +84 -0
- package/dist/ttd-sui-common/src/trade/abstract_sui_dex_trade_plus.d.ts +32 -0
- package/dist/ttd-sui-common/src/trade/abstract_sui_dex_trade_plus.js +216 -0
- package/dist/ttd-sui-common/src/trade/check/index.d.ts +1 -0
- package/dist/ttd-sui-common/src/trade/check/index.js +5 -0
- package/dist/ttd-sui-common/src/trade/check/tx_result_checker.d.ts +13 -0
- package/dist/ttd-sui-common/src/trade/check/tx_result_checker.js +111 -0
- package/dist/ttd-sui-common/src/trade/index.d.ts +4 -0
- package/dist/ttd-sui-common/src/trade/index.js +20 -0
- package/dist/ttd-sui-common/src/trade/parse/index.d.ts +1 -0
- package/dist/ttd-sui-common/src/trade/parse/index.js +5 -0
- package/dist/ttd-sui-common/src/trade/parse/sui_tx_parser.d.ts +13 -0
- package/dist/ttd-sui-common/src/trade/parse/sui_tx_parser.js +167 -0
- package/dist/ttd-sui-common/src/trade/send_tx/index.d.ts +10 -0
- package/dist/ttd-sui-common/src/trade/send_tx/index.js +48 -0
- package/dist/ttd-sui-common/src/trade/test/test_parse_sui_tx_result.d.ts +1 -0
- package/dist/ttd-sui-common/src/trade/test/test_parse_sui_tx_result.js +105 -0
- package/dist/ttd-sui-common/src/type/index.d.ts +18 -0
- package/dist/ttd-sui-common/src/type/index.js +2 -0
- package/dist/ttd-sui-common/src/utils/checkpoint_parse.d.ts +0 -0
- package/dist/ttd-sui-common/src/utils/checkpoint_parse.js +0 -0
- package/dist/ttd-sui-common/src/utils/decode.d.ts +2 -0
- package/dist/ttd-sui-common/src/utils/decode.js +43 -0
- package/dist/ttd-sui-common/src/utils/format.d.ts +1 -0
- package/dist/ttd-sui-common/src/utils/format.js +18 -0
- package/dist/ttd-sui-common/src/utils/index.d.ts +2 -0
- package/dist/ttd-sui-common/src/utils/index.js +18 -0
- package/dist/ttd-sui-market-data/src/sui_objects/config_manager.d.ts +22 -0
- package/dist/ttd-sui-market-data/src/sui_objects/config_manager.js +169 -0
- package/dist/ttd-sui-market-data/src/sui_objects/example.d.ts +1 -0
- package/dist/ttd-sui-market-data/src/sui_objects/example.js +72 -0
- package/dist/ttd-sui-market-data/src/sui_objects/index.d.ts +6 -0
- package/dist/ttd-sui-market-data/src/sui_objects/index.js +15 -0
- package/dist/ttd-sui-market-data/src/sui_objects/object_mgt.d.ts +47 -0
- package/dist/ttd-sui-market-data/src/sui_objects/object_mgt.js +483 -0
- package/dist/ttd-sui-market-data/src/sui_objects/types.d.ts +60 -0
- package/dist/ttd-sui-market-data/src/sui_objects/types.js +24 -0
- package/dist/ttd-sui-market-data/src/sui_objects/version_checker.d.ts +30 -0
- package/dist/ttd-sui-market-data/src/sui_objects/version_checker.js +207 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { AbastrcatTrade, AppConfig, TradeContext } from "@clonegod/ttd-core/dist";
|
|
2
|
+
import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
|
|
3
|
+
import { SuiClient } from "@mysten/sui/client";
|
|
4
|
+
import { SuiGrpcClient, SuiTxSender } from '../index';
|
|
5
|
+
import { SimpleRedisClient } from '../redis';
|
|
6
|
+
export declare abstract class AbstractSuiDexTradePlus extends AbastrcatTrade {
|
|
7
|
+
protected appConfig: AppConfig;
|
|
8
|
+
protected group_wallets: Ed25519Keypair[];
|
|
9
|
+
protected wallet: Ed25519Keypair;
|
|
10
|
+
protected walletMode: 'single' | 'multi';
|
|
11
|
+
sui_client: SuiClient;
|
|
12
|
+
grpcClient: SuiGrpcClient;
|
|
13
|
+
transactionSender: SuiTxSender;
|
|
14
|
+
protected redisClient: SimpleRedisClient;
|
|
15
|
+
walletAddresses: string[];
|
|
16
|
+
currentWalletAddress: string;
|
|
17
|
+
protected chainNameLower: string;
|
|
18
|
+
constructor(appConfig: AppConfig, grpcClient: SuiGrpcClient);
|
|
19
|
+
private initSuiClient;
|
|
20
|
+
init(): Promise<void>;
|
|
21
|
+
protected getWalletMode(): 'single' | 'multi';
|
|
22
|
+
protected getSingleWallet(): Ed25519Keypair;
|
|
23
|
+
protected getGroupWallets(): Ed25519Keypair[];
|
|
24
|
+
protected getWalletAddresses(): string[];
|
|
25
|
+
protected chooseWallet(context: TradeContext): Promise<Ed25519Keypair>;
|
|
26
|
+
protected determineInputOutputTokens(order_msg: any, pool_info: any): {
|
|
27
|
+
inputToken: any;
|
|
28
|
+
outputToken: any;
|
|
29
|
+
};
|
|
30
|
+
abstract execute(context: TradeContext, retryCount?: number): Promise<string>;
|
|
31
|
+
protected abstract initConfigs(): void;
|
|
32
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
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.AbstractSuiDexTradePlus = void 0;
|
|
16
|
+
const dist_1 = require("@clonegod/ttd-core/dist");
|
|
17
|
+
const ed25519_1 = require("@mysten/sui/keypairs/ed25519");
|
|
18
|
+
const client_1 = require("@mysten/sui/client");
|
|
19
|
+
const index_1 = require("../index");
|
|
20
|
+
const redis_1 = require("../redis");
|
|
21
|
+
const decimal_js_1 = __importDefault(require("decimal.js"));
|
|
22
|
+
class AbstractSuiDexTradePlus extends dist_1.AbastrcatTrade {
|
|
23
|
+
constructor(appConfig, grpcClient) {
|
|
24
|
+
super();
|
|
25
|
+
this.appConfig = appConfig;
|
|
26
|
+
this.walletMode = 'multi';
|
|
27
|
+
this.walletAddresses = [];
|
|
28
|
+
this.currentWalletAddress = '';
|
|
29
|
+
this.grpcClient = grpcClient;
|
|
30
|
+
this.initConfigs();
|
|
31
|
+
this.chainNameLower = this.appConfig.env_args.chain_id.toLowerCase();
|
|
32
|
+
this.redisClient = new redis_1.SimpleRedisClient(`${this.chainNameLower}:tx`);
|
|
33
|
+
}
|
|
34
|
+
initSuiClient() {
|
|
35
|
+
const sui_rpc_url = process.env.SUI_RPC_URL || 'https://fullnode.mainnet.sui.io:443';
|
|
36
|
+
this.sui_client = new client_1.SuiClient({ url: sui_rpc_url });
|
|
37
|
+
(0, dist_1.log_info)(`Sui客户端已初始化: ${sui_rpc_url}`);
|
|
38
|
+
}
|
|
39
|
+
init() {
|
|
40
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
this.initSuiClient();
|
|
42
|
+
const walletGroupIds = process.env.SUI_WALLET_GROUP_IDS || '';
|
|
43
|
+
this.walletMode = walletGroupIds && walletGroupIds.trim().split(',').length > 0 ? 'multi' : 'single';
|
|
44
|
+
if (this.walletMode === 'multi') {
|
|
45
|
+
let wallet_infos = (0, dist_1.load_wallet_multi)(walletGroupIds.split(','), false);
|
|
46
|
+
this.group_wallets = wallet_infos.map(info => ed25519_1.Ed25519Keypair.fromSecretKey(info.private_key));
|
|
47
|
+
this.walletAddresses = this.group_wallets.map(keypair => keypair.getPublicKey().toSuiAddress());
|
|
48
|
+
(0, dist_1.log_info)(`组钱包已初始化,数量: ${this.group_wallets.length}`, this.walletAddresses);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
const { private_key } = this.appConfig.trade_runtime.wallet;
|
|
52
|
+
this.wallet = ed25519_1.Ed25519Keypair.fromSecretKey(private_key);
|
|
53
|
+
this.currentWalletAddress = this.wallet.getPublicKey().toSuiAddress();
|
|
54
|
+
this.walletAddresses = [this.currentWalletAddress];
|
|
55
|
+
(0, dist_1.log_info)(`单钱包已初始化,walletAddress= ${this.currentWalletAddress}`);
|
|
56
|
+
}
|
|
57
|
+
this.transactionSender = new index_1.SuiTxSender(this.appConfig, this.sui_client, this.grpcClient);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
getWalletMode() {
|
|
61
|
+
return this.walletMode;
|
|
62
|
+
}
|
|
63
|
+
getSingleWallet() {
|
|
64
|
+
if (this.walletMode !== 'single' || !this.wallet) {
|
|
65
|
+
throw new Error('Single wallet not available in multi-wallet mode or not initialized');
|
|
66
|
+
}
|
|
67
|
+
return this.wallet;
|
|
68
|
+
}
|
|
69
|
+
getGroupWallets() {
|
|
70
|
+
if (this.walletMode !== 'multi' || !this.group_wallets) {
|
|
71
|
+
throw new Error('Group wallets not available in single-wallet mode or not initialized');
|
|
72
|
+
}
|
|
73
|
+
return this.group_wallets;
|
|
74
|
+
}
|
|
75
|
+
getWalletAddresses() {
|
|
76
|
+
return this.walletAddresses;
|
|
77
|
+
}
|
|
78
|
+
chooseWallet(context) {
|
|
79
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
80
|
+
var _a, _b;
|
|
81
|
+
if (this.getWalletMode() === 'single') {
|
|
82
|
+
return this.getSingleWallet();
|
|
83
|
+
}
|
|
84
|
+
const { inputToken } = this.determineInputOutputTokens(context.order_msg, context.pool_info);
|
|
85
|
+
console.log('inputToken', inputToken);
|
|
86
|
+
const requiredAmount = new decimal_js_1.default(context.order_msg.amount);
|
|
87
|
+
const wallet_assets = yield this.redisClient.hgetall('sui:wallet:assets');
|
|
88
|
+
if (!wallet_assets || Object.keys(wallet_assets).length === 0) {
|
|
89
|
+
throw new Error('没有找到钱包资产信息,请确保钱包监控服务正在运行');
|
|
90
|
+
}
|
|
91
|
+
const wallet_assets_map = {};
|
|
92
|
+
for (const [walletAddress, assetsJson] of Object.entries(wallet_assets)) {
|
|
93
|
+
try {
|
|
94
|
+
wallet_assets_map[walletAddress] = JSON.parse(assetsJson);
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
console.warn(`解析钱包资产数据失败: ${walletAddress}`, error);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const availableWallets = [];
|
|
101
|
+
const allWallets = [];
|
|
102
|
+
for (const [walletAddress, assets] of Object.entries(wallet_assets_map)) {
|
|
103
|
+
try {
|
|
104
|
+
const wallet = (_a = this.group_wallets) === null || _a === void 0 ? void 0 : _a.find(w => w.getPublicKey().toSuiAddress().toLowerCase() === walletAddress.toLowerCase());
|
|
105
|
+
if (!wallet) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const tokenAsset = (_b = assets.tokens) === null || _b === void 0 ? void 0 : _b.find((token) => token.tokenaddr.toLowerCase() === inputToken.address.toLowerCase());
|
|
109
|
+
let tokenBalance = (tokenAsset === null || tokenAsset === void 0 ? void 0 : tokenAsset.balance) || '0';
|
|
110
|
+
const balanceDecimal = new decimal_js_1.default(tokenBalance);
|
|
111
|
+
if (balanceDecimal.gte(requiredAmount)) {
|
|
112
|
+
availableWallets.push({
|
|
113
|
+
wallet,
|
|
114
|
+
balance: tokenBalance
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
console.log(`钱包 ${walletAddress} 余额不足: ${tokenBalance} ${inputToken.symbol} < ${requiredAmount} ${inputToken.symbol}`);
|
|
119
|
+
}
|
|
120
|
+
allWallets.push({
|
|
121
|
+
wallet,
|
|
122
|
+
balance: tokenBalance
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
console.warn(`处理钱包资产时出错: ${walletAddress}`, error);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (availableWallets.length === 0) {
|
|
130
|
+
let error_msg = `all wallets are insufficient, required: ${requiredAmount} ${inputToken.symbol}`;
|
|
131
|
+
(0, dist_1.log_warn)(error_msg);
|
|
132
|
+
allWallets.forEach((walletInfo, index) => {
|
|
133
|
+
const walletAddress = walletInfo.wallet.getPublicKey().toSuiAddress();
|
|
134
|
+
const shortAddress = walletAddress.substring(0, 6) + '...' + walletAddress.substring(walletAddress.length - 4);
|
|
135
|
+
console.log(`${index + 1}. ${shortAddress}: ${walletInfo.balance} ${inputToken.symbol}`);
|
|
136
|
+
});
|
|
137
|
+
throw new Error(error_msg);
|
|
138
|
+
}
|
|
139
|
+
console.log('availableWallets', availableWallets.map(w => w.wallet.getPublicKey().toSuiAddress()));
|
|
140
|
+
const wallet_last_used = yield this.redisClient.hgetall('sui:wallet:last_used');
|
|
141
|
+
for (const availableWallet of availableWallets) {
|
|
142
|
+
const walletAddress = availableWallet.wallet.getPublicKey().toSuiAddress();
|
|
143
|
+
const lastUsedData = wallet_last_used === null || wallet_last_used === void 0 ? void 0 : wallet_last_used[walletAddress];
|
|
144
|
+
if (lastUsedData) {
|
|
145
|
+
try {
|
|
146
|
+
const lastUsedInfo = JSON.parse(lastUsedData);
|
|
147
|
+
availableWallet.lastUsedAt = lastUsedInfo.lastUsedAt;
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
console.warn(`解析钱包最后使用时间失败: ${walletAddress}`, error);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
yield this.redisClient.hsetValue('sui:wallet:last_used', walletAddress, JSON.stringify({
|
|
155
|
+
lastUsedAt: 0,
|
|
156
|
+
lastUsedTime: new Date(0).toISOString()
|
|
157
|
+
}), 24 * 60 * 60);
|
|
158
|
+
availableWallet.lastUsedAt = 0;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
let selectedWallet;
|
|
162
|
+
let selectionStrategy;
|
|
163
|
+
if (availableWallets.length === 1) {
|
|
164
|
+
selectedWallet = availableWallets[0].wallet;
|
|
165
|
+
selectionStrategy = 'OnlyOne';
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
const hasUsageHistory = wallet_last_used && Object.keys(wallet_last_used).length > 0;
|
|
169
|
+
if (hasUsageHistory) {
|
|
170
|
+
availableWallets.sort((a, b) => {
|
|
171
|
+
const aTime = a.lastUsedAt || 0;
|
|
172
|
+
const bTime = b.lastUsedAt || 0;
|
|
173
|
+
return aTime - bTime;
|
|
174
|
+
});
|
|
175
|
+
selectedWallet = availableWallets[0].wallet;
|
|
176
|
+
selectionStrategy = 'MaxLastUsed';
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
availableWallets.sort((a, b) => {
|
|
180
|
+
const aBalance = new decimal_js_1.default(a.balance);
|
|
181
|
+
const bBalance = new decimal_js_1.default(b.balance);
|
|
182
|
+
return bBalance.cmp(aBalance);
|
|
183
|
+
});
|
|
184
|
+
selectedWallet = availableWallets[0].wallet;
|
|
185
|
+
selectionStrategy = 'MaxBalance';
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const selectedWalletAddress = selectedWallet.getPublicKey().toSuiAddress();
|
|
189
|
+
yield this.redisClient.hsetValue('sui:wallet:last_used', selectedWalletAddress, JSON.stringify({
|
|
190
|
+
lastUsedAt: Date.now(),
|
|
191
|
+
lastUsedTime: new Date().toISOString()
|
|
192
|
+
}), 24 * 60 * 60);
|
|
193
|
+
const selectedWalletInfo = availableWallets.find(w => w.wallet.getPublicKey().toSuiAddress() === selectedWalletAddress);
|
|
194
|
+
(0, dist_1.log_info)(`Choose wallet: ${selectionStrategy} -> ${selectedWalletAddress}, balance: ${selectedWalletInfo === null || selectedWalletInfo === void 0 ? void 0 : selectedWalletInfo.balance} ${inputToken.symbol}, required: ${requiredAmount} ${inputToken.symbol}`);
|
|
195
|
+
return selectedWallet;
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
determineInputOutputTokens(order_msg, pool_info) {
|
|
199
|
+
const { aToB } = order_msg;
|
|
200
|
+
const { tokenA, tokenB, quote_token } = pool_info;
|
|
201
|
+
const quoteToken = [tokenA, tokenB].find(token => token.symbol === quote_token);
|
|
202
|
+
const nonQuoteToken = [tokenA, tokenB].find(token => token.symbol !== quote_token);
|
|
203
|
+
const inputToken = aToB ? nonQuoteToken : quoteToken;
|
|
204
|
+
const outputToken = aToB ? quoteToken : nonQuoteToken;
|
|
205
|
+
if (!inputToken || !outputToken) {
|
|
206
|
+
throw new Error(`无法确定输入/输出代币: ${JSON.stringify({
|
|
207
|
+
tokenA: tokenA.symbol,
|
|
208
|
+
tokenB: tokenB.symbol,
|
|
209
|
+
quote: quote_token,
|
|
210
|
+
aToB
|
|
211
|
+
})}`);
|
|
212
|
+
}
|
|
213
|
+
return { inputToken, outputToken };
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
exports.AbstractSuiDexTradePlus = AbstractSuiDexTradePlus;
|
package/dist/trade/index.d.ts
CHANGED
package/dist/trade/index.js
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SUI_TOKEN_ADDRESS = void 0;
|
|
4
|
+
var SUI_TOKEN_ADDRESS;
|
|
5
|
+
(function (SUI_TOKEN_ADDRESS) {
|
|
6
|
+
SUI_TOKEN_ADDRESS["SHORT"] = "0x2::sui::SUI";
|
|
7
|
+
SUI_TOKEN_ADDRESS["LONG"] = "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI";
|
|
8
|
+
})(SUI_TOKEN_ADDRESS || (exports.SUI_TOKEN_ADDRESS = SUI_TOKEN_ADDRESS = {}));
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare class GasPriceCache {
|
|
2
|
+
private static instance;
|
|
3
|
+
private cachedGasPrice;
|
|
4
|
+
private lastUpdateTime;
|
|
5
|
+
private updateInterval;
|
|
6
|
+
private ledgerService;
|
|
7
|
+
private refreshTimer?;
|
|
8
|
+
private constructor();
|
|
9
|
+
static getInstance(ledgerService: any): GasPriceCache;
|
|
10
|
+
getGasPrice(): Promise<number>;
|
|
11
|
+
refreshGasPrice(): Promise<void>;
|
|
12
|
+
private startAutoRefresh;
|
|
13
|
+
stopAutoRefresh(): void;
|
|
14
|
+
getCacheInfo(): {
|
|
15
|
+
cachedGasPrice: number;
|
|
16
|
+
lastUpdateTime: number;
|
|
17
|
+
isExpired: boolean;
|
|
18
|
+
timeUntilNextRefresh: number;
|
|
19
|
+
};
|
|
20
|
+
destroy(): void;
|
|
21
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
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.GasPriceCache = void 0;
|
|
13
|
+
const dist_1 = require("@clonegod/ttd-core/dist");
|
|
14
|
+
class GasPriceCache {
|
|
15
|
+
constructor(ledgerService) {
|
|
16
|
+
this.cachedGasPrice = 0;
|
|
17
|
+
this.lastUpdateTime = 0;
|
|
18
|
+
this.updateInterval = 60 * 60 * 1000;
|
|
19
|
+
this.ledgerService = ledgerService;
|
|
20
|
+
this.startAutoRefresh();
|
|
21
|
+
}
|
|
22
|
+
static getInstance(ledgerService) {
|
|
23
|
+
if (!GasPriceCache.instance) {
|
|
24
|
+
GasPriceCache.instance = new GasPriceCache(ledgerService);
|
|
25
|
+
}
|
|
26
|
+
return GasPriceCache.instance;
|
|
27
|
+
}
|
|
28
|
+
getGasPrice() {
|
|
29
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
30
|
+
if (Date.now() - this.lastUpdateTime > this.updateInterval || this.cachedGasPrice === 0) {
|
|
31
|
+
yield this.refreshGasPrice();
|
|
32
|
+
}
|
|
33
|
+
return this.cachedGasPrice;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
refreshGasPrice() {
|
|
37
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
38
|
+
try {
|
|
39
|
+
const epochRes = yield this.ledgerService.getEpoch();
|
|
40
|
+
this.cachedGasPrice = Number(epochRes['epoch']['reference_gas_price']);
|
|
41
|
+
this.lastUpdateTime = Date.now();
|
|
42
|
+
(0, dist_1.log_info)(`refreshGasPrice success: ${this.cachedGasPrice} MIST`);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
(0, dist_1.log_error)('refresh gas price failed', error);
|
|
46
|
+
this.cachedGasPrice = Number(process.env.DEFAULT_GAS_PRICE || '600');
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
startAutoRefresh() {
|
|
51
|
+
this.refreshGasPrice().catch(error => {
|
|
52
|
+
(0, dist_1.log_error)('initial gas price refresh failed', error);
|
|
53
|
+
});
|
|
54
|
+
this.refreshTimer = setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
55
|
+
yield this.refreshGasPrice();
|
|
56
|
+
}), this.updateInterval);
|
|
57
|
+
(0, dist_1.log_info)('Gas price auto refresh started, refresh interval: 5 minutes');
|
|
58
|
+
}
|
|
59
|
+
stopAutoRefresh() {
|
|
60
|
+
if (this.refreshTimer) {
|
|
61
|
+
clearInterval(this.refreshTimer);
|
|
62
|
+
this.refreshTimer = undefined;
|
|
63
|
+
(0, dist_1.log_info)('Gas price auto refresh stopped');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
getCacheInfo() {
|
|
67
|
+
const now = Date.now();
|
|
68
|
+
const timeSinceLastUpdate = now - this.lastUpdateTime;
|
|
69
|
+
const isExpired = timeSinceLastUpdate > this.updateInterval;
|
|
70
|
+
const timeUntilNextRefresh = Math.max(0, this.updateInterval - timeSinceLastUpdate);
|
|
71
|
+
return {
|
|
72
|
+
cachedGasPrice: this.cachedGasPrice,
|
|
73
|
+
lastUpdateTime: this.lastUpdateTime,
|
|
74
|
+
isExpired,
|
|
75
|
+
timeUntilNextRefresh
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
destroy() {
|
|
79
|
+
this.stopAutoRefresh();
|
|
80
|
+
GasPriceCache.instance = null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
exports.GasPriceCache = GasPriceCache;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as grpc from '@grpc/grpc-js';
|
|
2
|
+
export declare class GrpcConnection {
|
|
3
|
+
private static instance;
|
|
4
|
+
private channel;
|
|
5
|
+
private endpoint;
|
|
6
|
+
private metadata;
|
|
7
|
+
private constructor();
|
|
8
|
+
static getInstance(grpc_endpoint: string, grpc_token: string): GrpcConnection;
|
|
9
|
+
private getChannel;
|
|
10
|
+
createServiceClient<T>(protoFileName: string, serviceName: string): T;
|
|
11
|
+
getMetadata(): grpc.Metadata;
|
|
12
|
+
close(): void;
|
|
13
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.GrpcConnection = void 0;
|
|
37
|
+
const grpc = __importStar(require("@grpc/grpc-js"));
|
|
38
|
+
const protoLoader = __importStar(require("@grpc/proto-loader"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
class GrpcConnection {
|
|
41
|
+
constructor(grpc_endpoint, grpc_token) {
|
|
42
|
+
this.channel = null;
|
|
43
|
+
this.endpoint = grpc_endpoint;
|
|
44
|
+
this.metadata = new grpc.Metadata();
|
|
45
|
+
this.metadata.add('x-token', grpc_token);
|
|
46
|
+
}
|
|
47
|
+
static getInstance(grpc_endpoint, grpc_token) {
|
|
48
|
+
if (!GrpcConnection.instance) {
|
|
49
|
+
GrpcConnection.instance = new GrpcConnection(grpc_endpoint, grpc_token);
|
|
50
|
+
}
|
|
51
|
+
return GrpcConnection.instance;
|
|
52
|
+
}
|
|
53
|
+
getChannel() {
|
|
54
|
+
if (!this.channel) {
|
|
55
|
+
this.channel = new grpc.Channel(this.endpoint, grpc.credentials.createSsl(), {
|
|
56
|
+
'grpc.keepalive_time_ms': 120000,
|
|
57
|
+
'grpc.keepalive_timeout_ms': 20000,
|
|
58
|
+
'grpc.keepalive_permit_without_calls': 0,
|
|
59
|
+
'grpc.http2.max_pings_without_data': 0,
|
|
60
|
+
'grpc.http2.min_time_between_pings_ms': 120000,
|
|
61
|
+
'grpc.http2.min_ping_interval_without_data_ms': 120000
|
|
62
|
+
});
|
|
63
|
+
console.log(`创建 gRPC 通道: ${this.endpoint}`);
|
|
64
|
+
}
|
|
65
|
+
return this.channel;
|
|
66
|
+
}
|
|
67
|
+
createServiceClient(protoFileName, serviceName) {
|
|
68
|
+
var _a, _b, _c;
|
|
69
|
+
const protoPath = path.join(__dirname, 'protos/sui/rpc/v2beta2', protoFileName);
|
|
70
|
+
const packageDefinition = protoLoader.loadSync(protoPath, {
|
|
71
|
+
keepCase: true,
|
|
72
|
+
longs: String,
|
|
73
|
+
enums: String,
|
|
74
|
+
defaults: true,
|
|
75
|
+
oneofs: true,
|
|
76
|
+
includeDirs: [path.join(__dirname, 'protos')]
|
|
77
|
+
});
|
|
78
|
+
const protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
|
|
79
|
+
const service = (_c = (_b = (_a = protoDescriptor.sui) === null || _a === void 0 ? void 0 : _a.rpc) === null || _b === void 0 ? void 0 : _b.v2beta2) === null || _c === void 0 ? void 0 : _c[serviceName];
|
|
80
|
+
if (!service) {
|
|
81
|
+
throw new Error(`Service ${serviceName} not found in proto file`);
|
|
82
|
+
}
|
|
83
|
+
const channel = this.getChannel();
|
|
84
|
+
return new service(this.endpoint, grpc.credentials.createSsl(), {
|
|
85
|
+
channelOverride: channel
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
getMetadata() {
|
|
89
|
+
return this.metadata;
|
|
90
|
+
}
|
|
91
|
+
close() {
|
|
92
|
+
if (this.channel) {
|
|
93
|
+
this.channel.close();
|
|
94
|
+
this.channel = null;
|
|
95
|
+
console.log('gRPC 通道已关闭');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
exports.GrpcConnection = GrpcConnection;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { GrpcConnection } from './grpc-connection';
|
|
2
|
+
export { LedgerService } from './ledger-service';
|
|
3
|
+
export { LiveDataService } from './live-data-service';
|
|
4
|
+
export { TransactionService } from './transaction-service';
|
|
5
|
+
export { SubscriptionService } from './subscription-service';
|
|
6
|
+
export { SuiGrpcClient } from './sui-grpc-client';
|
|
7
|
+
export { GasPriceCache } from './gas-price-cache';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GasPriceCache = exports.SuiGrpcClient = exports.SubscriptionService = exports.TransactionService = exports.LiveDataService = exports.LedgerService = exports.GrpcConnection = void 0;
|
|
4
|
+
var grpc_connection_1 = require("./grpc-connection");
|
|
5
|
+
Object.defineProperty(exports, "GrpcConnection", { enumerable: true, get: function () { return grpc_connection_1.GrpcConnection; } });
|
|
6
|
+
var ledger_service_1 = require("./ledger-service");
|
|
7
|
+
Object.defineProperty(exports, "LedgerService", { enumerable: true, get: function () { return ledger_service_1.LedgerService; } });
|
|
8
|
+
var live_data_service_1 = require("./live-data-service");
|
|
9
|
+
Object.defineProperty(exports, "LiveDataService", { enumerable: true, get: function () { return live_data_service_1.LiveDataService; } });
|
|
10
|
+
var transaction_service_1 = require("./transaction-service");
|
|
11
|
+
Object.defineProperty(exports, "TransactionService", { enumerable: true, get: function () { return transaction_service_1.TransactionService; } });
|
|
12
|
+
var subscription_service_1 = require("./subscription-service");
|
|
13
|
+
Object.defineProperty(exports, "SubscriptionService", { enumerable: true, get: function () { return subscription_service_1.SubscriptionService; } });
|
|
14
|
+
var sui_grpc_client_1 = require("./sui-grpc-client");
|
|
15
|
+
Object.defineProperty(exports, "SuiGrpcClient", { enumerable: true, get: function () { return sui_grpc_client_1.SuiGrpcClient; } });
|
|
16
|
+
var gas_price_cache_1 = require("./gas-price-cache");
|
|
17
|
+
Object.defineProperty(exports, "GasPriceCache", { enumerable: true, get: function () { return gas_price_cache_1.GasPriceCache; } });
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { GrpcConnection } from './grpc-connection';
|
|
2
|
+
export declare class LedgerService {
|
|
3
|
+
private ledgerClient;
|
|
4
|
+
private connection;
|
|
5
|
+
constructor(connection: GrpcConnection);
|
|
6
|
+
getServiceInfo(): Promise<unknown>;
|
|
7
|
+
getEpoch(epoch?: number, includeGasPrice?: boolean): Promise<unknown>;
|
|
8
|
+
getCheckpoint(checkpointId?: string): Promise<any>;
|
|
9
|
+
getObject(objectId: string, readMask?: string[]): Promise<unknown>;
|
|
10
|
+
batchGetObjects(objectIds: string[], readMask?: string[]): Promise<unknown>;
|
|
11
|
+
getTransaction(digest: string, readMask?: string[]): Promise<unknown>;
|
|
12
|
+
}
|