@clonegod/ttd-sui-common 1.0.101 → 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.
Files changed (126) hide show
  1. package/dist/appconfig/SuiQuoteAppConfig.d.ts +10 -0
  2. package/dist/appconfig/SuiQuoteAppConfig.js +35 -0
  3. package/dist/appconfig/SuiTradeAppConfig.d.ts +7 -0
  4. package/dist/appconfig/SuiTradeAppConfig.js +13 -0
  5. package/dist/appconfig/ensure_core_env.d.ts +1 -0
  6. package/dist/appconfig/ensure_core_env.js +18 -0
  7. package/dist/appconfig/index.d.ts +5 -0
  8. package/dist/appconfig/index.js +21 -0
  9. package/dist/appconfig/sui_dex_env_args.d.ts +5 -0
  10. package/dist/appconfig/sui_dex_env_args.js +28 -0
  11. package/dist/appconfig/sui_env_args.d.ts +4 -0
  12. package/dist/appconfig/sui_env_args.js +20 -0
  13. package/dist/grpc/gas-price-cache.js +19 -32
  14. package/dist/grpc/grpc-connection.js +5 -3
  15. package/dist/grpc/grpc_provider_registry.d.ts +14 -0
  16. package/dist/grpc/grpc_provider_registry.js +60 -0
  17. package/dist/grpc/index.d.ts +3 -0
  18. package/dist/grpc/index.js +13 -1
  19. package/dist/grpc/ledger-service.js +107 -128
  20. package/dist/grpc/proto_value.d.ts +4 -0
  21. package/dist/grpc/proto_value.js +59 -0
  22. package/dist/grpc/state-service.d.ts +1 -0
  23. package/dist/grpc/state-service.js +99 -102
  24. package/dist/grpc/sui-grpc-client.js +2 -13
  25. package/dist/grpc/sui_object_reader.d.ts +15 -0
  26. package/dist/grpc/sui_object_reader.js +60 -0
  27. package/dist/grpc/transaction-service.js +26 -37
  28. package/dist/index.d.ts +1 -1
  29. package/dist/index.js +1 -1
  30. package/dist/quote/abstract_dex_quote.d.ts +60 -0
  31. package/dist/quote/abstract_dex_quote.js +186 -0
  32. package/dist/quote/chain_ops.d.ts +17 -0
  33. package/dist/quote/chain_ops.js +52 -0
  34. package/dist/quote/index.d.ts +7 -0
  35. package/dist/quote/index.js +7 -0
  36. package/dist/quote/pool_event.d.ts +21 -0
  37. package/dist/quote/pool_event.js +6 -0
  38. package/dist/quote/pricing/token_price_cache.js +18 -29
  39. package/dist/quote/quote_amount.d.ts +4 -0
  40. package/dist/quote/quote_amount.js +24 -0
  41. package/dist/quote/quote_trace.d.ts +16 -0
  42. package/dist/quote/quote_trace.js +40 -0
  43. package/dist/quote/tick/clmm_v3_engine.d.ts +32 -0
  44. package/dist/quote/tick/clmm_v3_engine.js +48 -0
  45. package/dist/quote/tick/index.d.ts +4 -0
  46. package/dist/quote/tick/index.js +20 -0
  47. package/dist/quote/tick/local_clmm_state.d.ts +17 -0
  48. package/dist/quote/tick/local_clmm_state.js +22 -0
  49. package/dist/quote/tick/sui_clmm_tick_cache.d.ts +42 -0
  50. package/dist/quote/tick/sui_clmm_tick_cache.js +163 -0
  51. package/dist/quote/tick/sui_tick_data_provider.d.ts +2 -0
  52. package/dist/quote/tick/sui_tick_data_provider.js +6 -0
  53. package/dist/quote/verify/index.d.ts +1 -0
  54. package/dist/quote/verify/index.js +17 -0
  55. package/dist/quote/verify/quote_price_verify.d.ts +30 -0
  56. package/dist/quote/verify/quote_price_verify.js +247 -0
  57. package/dist/redis/redis_client.d.ts +1 -0
  58. package/dist/redis/redis_client.js +88 -117
  59. package/dist/rpc/index.js +59 -75
  60. package/dist/test/test.js +1 -1
  61. package/dist/test/test_checkpoint.js +4 -13
  62. package/dist/test/test_grpc.js +32 -41
  63. package/dist/trade/abstract_sui_dex_trade.d.ts +43 -0
  64. package/dist/trade/abstract_sui_dex_trade.js +380 -0
  65. package/dist/trade/abstract_sui_dex_trade_plus.d.ts +3 -1
  66. package/dist/trade/abstract_sui_dex_trade_plus.js +232 -212
  67. package/dist/trade/check/tx_result_checker.js +65 -75
  68. package/dist/trade/coin/index.d.ts +1 -0
  69. package/dist/trade/coin/index.js +17 -0
  70. package/dist/trade/coin/lua_scripts.d.ts +5 -0
  71. package/dist/trade/coin/lua_scripts.js +130 -0
  72. package/dist/trade/coin/types.d.ts +30 -0
  73. package/dist/trade/coin/types.js +2 -0
  74. package/dist/trade/coin/wallet_coin_ledger.d.ts +22 -0
  75. package/dist/trade/coin/wallet_coin_ledger.js +85 -0
  76. package/dist/trade/executor/central_executor.d.ts +72 -0
  77. package/dist/trade/executor/central_executor.js +240 -0
  78. package/dist/trade/executor/coin_cache.d.ts +21 -0
  79. package/dist/trade/executor/coin_cache.js +143 -0
  80. package/dist/trade/executor/coin_maintainer.d.ts +32 -0
  81. package/dist/trade/executor/coin_maintainer.js +123 -0
  82. package/dist/trade/executor/core_channel.d.ts +38 -0
  83. package/dist/trade/executor/core_channel.js +131 -0
  84. package/dist/trade/executor/data_channel.d.ts +27 -0
  85. package/dist/trade/executor/data_channel.js +2 -0
  86. package/dist/trade/executor/effects.d.ts +16 -0
  87. package/dist/trade/executor/effects.js +63 -0
  88. package/dist/trade/executor/executor_client.d.ts +13 -0
  89. package/dist/trade/executor/executor_client.js +55 -0
  90. package/dist/trade/executor/executor_protocol.d.ts +26 -0
  91. package/dist/trade/executor/executor_protocol.js +32 -0
  92. package/dist/trade/executor/executor_server.d.ts +8 -0
  93. package/dist/trade/executor/executor_server.js +33 -0
  94. package/dist/trade/executor/executor_ws_client.d.ts +13 -0
  95. package/dist/trade/executor/executor_ws_client.js +58 -0
  96. package/dist/trade/executor/grpc_channel.d.ts +14 -0
  97. package/dist/trade/executor/grpc_channel.js +73 -0
  98. package/dist/trade/executor/index.d.ts +7 -0
  99. package/dist/trade/executor/index.js +23 -0
  100. package/dist/trade/executor/json_rpc_channel.d.ts +14 -0
  101. package/dist/trade/executor/json_rpc_channel.js +77 -0
  102. package/dist/trade/index.d.ts +5 -1
  103. package/dist/trade/index.js +5 -1
  104. package/dist/trade/parse/sui_tx_parser.js +98 -81
  105. package/dist/trade/send_tx/index.js +34 -47
  106. package/dist/trade/swap/builders/bluefin.d.ts +9 -0
  107. package/dist/trade/swap/builders/bluefin.js +60 -0
  108. package/dist/trade/swap/builders/cetus_magma.d.ts +13 -0
  109. package/dist/trade/swap/builders/cetus_magma.js +52 -0
  110. package/dist/trade/swap/builders/momentum.d.ts +9 -0
  111. package/dist/trade/swap/builders/momentum.js +80 -0
  112. package/dist/trade/swap/dex_swap_config.d.ts +28 -0
  113. package/dist/trade/swap/dex_swap_config.js +40 -0
  114. package/dist/trade/swap/index.d.ts +7 -0
  115. package/dist/trade/swap/index.js +36 -0
  116. package/dist/trade/swap/types.d.ts +20 -0
  117. package/dist/trade/swap/types.js +2 -0
  118. package/dist/trade/test/test_parse_sui_tx_result.js +33 -44
  119. package/dist/trade/tx_result_channel.d.ts +7 -0
  120. package/dist/trade/tx_result_channel.js +7 -0
  121. package/dist/utils/decode.js +1 -2
  122. package/dist/utils/index.d.ts +1 -0
  123. package/dist/utils/index.js +1 -0
  124. package/dist/utils/trade_direction.d.ts +14 -0
  125. package/dist/utils/trade_direction.js +23 -0
  126. package/package.json +3 -2
@@ -1,13 +1,4 @@
1
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
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
12
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
4
  };
@@ -20,6 +11,8 @@ const transactions_1 = require("@mysten/sui/transactions");
20
11
  const decimal_js_1 = __importDefault(require("decimal.js"));
21
12
  const index_1 = require("../index");
22
13
  const redis_1 = require("../redis");
14
+ const executor_1 = require("./executor");
15
+ const tx_result_channel_1 = require("./tx_result_channel");
23
16
  class AbstractSuiDexTradePlus extends dist_1.AbastrcatTrade {
24
17
  constructor(appConfig, grpcClient) {
25
18
  super();
@@ -31,26 +24,36 @@ class AbstractSuiDexTradePlus extends dist_1.AbastrcatTrade {
31
24
  this.chainNameLower = this.appConfig.env_args.chain_id.toLowerCase();
32
25
  this.redisClient = new redis_1.SimpleRedisClient(`${this.chainNameLower}:tx`);
33
26
  }
34
- init() {
35
- return __awaiter(this, void 0, void 0, function* () {
36
- this.initSuiClient();
37
- yield this.initConfigs();
38
- const walletGroupIds = process.env.SUI_WALLET_GROUP_IDS || process.env.WALLET_GROUP_IDS || '';
39
- this.walletMode = walletGroupIds && walletGroupIds.trim().split(',').length > 0 ? 'multi' : 'single';
40
- if (this.walletMode === 'multi') {
41
- let wallet_infos = (0, dist_1.load_wallet_multi)(walletGroupIds.split(','), false);
42
- this.group_wallets = wallet_infos.map(info => ed25519_1.Ed25519Keypair.fromSecretKey(info.private_key));
43
- this.walletAddresses = this.group_wallets.map(keypair => keypair.getPublicKey().toSuiAddress());
44
- (0, dist_1.log_info)(`init wallet mode: multi, wallet count: ${this.group_wallets.length}, walletAddresses: ${this.walletAddresses}`);
27
+ async init() {
28
+ this.initSuiClient();
29
+ await this.initConfigs();
30
+ const walletGroupIds = process.env.SUI_WALLET_GROUP_IDS || process.env.WALLET_GROUP_IDS || '';
31
+ this.walletMode = walletGroupIds && walletGroupIds.trim().split(',').length > 0 ? 'multi' : 'single';
32
+ if (this.walletMode === 'multi') {
33
+ let wallet_infos = (0, dist_1.load_wallet_multi)(walletGroupIds.split(','), false);
34
+ this.group_wallets = wallet_infos.map(info => ed25519_1.Ed25519Keypair.fromSecretKey(info.private_key));
35
+ this.walletAddresses = this.group_wallets.map(keypair => keypair.getPublicKey().toSuiAddress());
36
+ (0, dist_1.log_info)(`init wallet mode: multi, wallet count: ${this.group_wallets.length}, walletAddresses: ${this.walletAddresses}`);
37
+ }
38
+ else {
39
+ const { private_key } = this.appConfig.trade_runtime.wallet;
40
+ this.wallet = ed25519_1.Ed25519Keypair.fromSecretKey(private_key);
41
+ this.currentWalletAddress = this.wallet.getPublicKey().toSuiAddress();
42
+ this.walletAddresses = [this.currentWalletAddress];
43
+ (0, dist_1.log_info)(`init wallet mode: single, walletAddress= ${this.currentWalletAddress}`);
44
+ }
45
+ this.transactionSender = new index_1.SuiTxSender(this.appConfig, this.sui_client, this.grpcClient);
46
+ this.executorClient = new executor_1.ExecutorWsClient();
47
+ const txResultChannel = (0, tx_result_channel_1.get_sui_tx_result_channel)();
48
+ this.appConfig.arb_cache.redis_cmd.subscribe(txResultChannel, (message) => {
49
+ try {
50
+ const msg = JSON.parse(message);
51
+ if (msg.digest)
52
+ this.appConfig.emit(`SUI_TX_RESULT_${msg.digest}`, msg.digest);
45
53
  }
46
- else {
47
- const { private_key } = this.appConfig.trade_runtime.wallet;
48
- this.wallet = ed25519_1.Ed25519Keypair.fromSecretKey(private_key);
49
- this.currentWalletAddress = this.wallet.getPublicKey().toSuiAddress();
50
- this.walletAddresses = [this.currentWalletAddress];
51
- (0, dist_1.log_info)(`init wallet mode: single, walletAddress= ${this.currentWalletAddress}`);
54
+ catch (e) {
55
+ (0, dist_1.log_warn)(`[trade] bad tx result msg`, message);
52
56
  }
53
- this.transactionSender = new index_1.SuiTxSender(this.appConfig, this.sui_client, this.grpcClient);
54
57
  });
55
58
  }
56
59
  initSuiClient() {
@@ -76,152 +79,149 @@ class AbstractSuiDexTradePlus extends dist_1.AbastrcatTrade {
76
79
  getWalletAddresses() {
77
80
  return this.walletAddresses;
78
81
  }
79
- chooseWallet(context) {
80
- return __awaiter(this, void 0, void 0, function* () {
81
- var _a, _b;
82
- if (this.getWalletMode() === 'single') {
83
- return this.getSingleWallet();
82
+ async chooseWallet(context) {
83
+ if (this.getWalletMode() === 'single') {
84
+ return this.getSingleWallet();
85
+ }
86
+ const lockIdentifier = `choose_wallet`;
87
+ const lockKey = `${this.chainNameLower}:lock:${lockIdentifier}`;
88
+ const lockValue = `${Math.random().toString(36).substring(2, 15)}`;
89
+ let lockAcquired = false;
90
+ const start_time = Date.now();
91
+ const maxRetryTime = 200;
92
+ const retryDelay = 20;
93
+ do {
94
+ lockAcquired = await this.redisClient.acquireLock(lockKey, lockValue, 2);
95
+ if (lockAcquired) {
96
+ break;
84
97
  }
85
- const lockIdentifier = `choose_wallet`;
86
- const lockKey = `${this.chainNameLower}:lock:${lockIdentifier}`;
87
- const lockValue = `${Math.random().toString(36).substring(2, 15)}`;
88
- let lockAcquired = false;
89
- const start_time = Date.now();
90
- const maxRetryTime = 200;
91
- const retryDelay = 20;
92
- do {
93
- lockAcquired = yield this.redisClient.acquireLock(lockKey, lockValue, 2);
94
- if (lockAcquired) {
95
- break;
96
- }
97
- yield (0, dist_1.sleep)(retryDelay);
98
- } while (!lockAcquired && Date.now() - start_time < maxRetryTime);
99
- if (!lockAcquired) {
100
- throw new Error(`choose wallet, acquire lock failed: ${lockKey}, took ${Date.now() - start_time}ms`);
98
+ await (0, dist_1.sleep)(retryDelay);
99
+ } while (!lockAcquired && Date.now() - start_time < maxRetryTime);
100
+ if (!lockAcquired) {
101
+ throw new Error(`choose wallet, acquire lock failed: ${lockKey}, took ${Date.now() - start_time}ms`);
102
+ }
103
+ (0, dist_1.log_info)(`choose wallet, acquire lock success: ${lockKey}, took ${Date.now() - start_time}ms`);
104
+ try {
105
+ const { inputToken } = this.determineInputOutputTokens(context.order_msg, context.pool_info);
106
+ console.log('inputToken', inputToken);
107
+ const requiredAmount = new decimal_js_1.default(context.order_msg.amount);
108
+ const wallet_assets = await this.redisClient.hgetall('sui:wallet:assets');
109
+ if (!wallet_assets || Object.keys(wallet_assets).length === 0) {
110
+ throw new Error('没有找到钱包资产信息,请确保钱包监控服务正在运行');
101
111
  }
102
- (0, dist_1.log_info)(`choose wallet, acquire lock success: ${lockKey}, took ${Date.now() - start_time}ms`);
103
- try {
104
- const { inputToken } = this.determineInputOutputTokens(context.order_msg, context.pool_info);
105
- console.log('inputToken', inputToken);
106
- const requiredAmount = new decimal_js_1.default(context.order_msg.amount);
107
- const wallet_assets = yield this.redisClient.hgetall('sui:wallet:assets');
108
- if (!wallet_assets || Object.keys(wallet_assets).length === 0) {
109
- throw new Error('没有找到钱包资产信息,请确保钱包监控服务正在运行');
112
+ const wallet_assets_map = {};
113
+ for (const [walletAddress, assetsJson] of Object.entries(wallet_assets)) {
114
+ try {
115
+ wallet_assets_map[walletAddress] = JSON.parse(assetsJson);
110
116
  }
111
- const wallet_assets_map = {};
112
- for (const [walletAddress, assetsJson] of Object.entries(wallet_assets)) {
113
- try {
114
- wallet_assets_map[walletAddress] = JSON.parse(assetsJson);
115
- }
116
- catch (error) {
117
- console.warn(`解析钱包资产数据失败: ${walletAddress}`, error);
118
- }
117
+ catch (error) {
118
+ console.warn(`解析钱包资产数据失败: ${walletAddress}`, error);
119
119
  }
120
- const availableWallets = [];
121
- const allWallets = [];
122
- for (const [walletAddress, assets] of Object.entries(wallet_assets_map)) {
123
- try {
124
- const wallet = (_a = this.group_wallets) === null || _a === void 0 ? void 0 : _a.find(w => w.getPublicKey().toSuiAddress().toLowerCase() === walletAddress.toLowerCase());
125
- if (!wallet) {
126
- continue;
127
- }
128
- const tokenAsset = (_b = assets.tokens) === null || _b === void 0 ? void 0 : _b.find((token) => (0, index_1.normalizeSuiTokenAddress)(token.address) === (0, index_1.normalizeSuiTokenAddress)(inputToken.address));
129
- let tokenBalance = (tokenAsset === null || tokenAsset === void 0 ? void 0 : tokenAsset.balance) || '0';
130
- const balanceDecimal = new decimal_js_1.default(tokenBalance);
131
- if (balanceDecimal.gte(requiredAmount)) {
132
- availableWallets.push({
133
- wallet,
134
- balance: tokenBalance
135
- });
136
- }
137
- else {
138
- console.log(`钱包 ${walletAddress} 余额不足: ${tokenBalance} ${inputToken.symbol} < ${requiredAmount} ${inputToken.symbol}`);
139
- }
140
- allWallets.push({
120
+ }
121
+ const availableWallets = [];
122
+ const allWallets = [];
123
+ for (const [walletAddress, assets] of Object.entries(wallet_assets_map)) {
124
+ try {
125
+ const wallet = this.group_wallets?.find(w => w.getPublicKey().toSuiAddress().toLowerCase() === walletAddress.toLowerCase());
126
+ if (!wallet) {
127
+ continue;
128
+ }
129
+ const tokenAsset = assets.tokens?.find((token) => (0, index_1.normalizeSuiTokenAddress)(token.address) === (0, index_1.normalizeSuiTokenAddress)(inputToken.address));
130
+ let tokenBalance = tokenAsset?.balance || '0';
131
+ const balanceDecimal = new decimal_js_1.default(tokenBalance);
132
+ if (balanceDecimal.gte(requiredAmount)) {
133
+ availableWallets.push({
141
134
  wallet,
142
135
  balance: tokenBalance
143
136
  });
144
137
  }
145
- catch (error) {
146
- console.warn(`处理钱包资产时出错: ${walletAddress}`, error);
138
+ else {
139
+ console.log(`钱包 ${walletAddress} 余额不足: ${tokenBalance} ${inputToken.symbol} < ${requiredAmount} ${inputToken.symbol}`);
147
140
  }
148
- }
149
- if (availableWallets.length === 0) {
150
- let error_msg = `all wallets are insufficient, required: ${requiredAmount} ${inputToken.symbol}`;
151
- (0, dist_1.log_warn)(error_msg);
152
- allWallets.forEach((walletInfo, index) => {
153
- const walletAddress = walletInfo.wallet.getPublicKey().toSuiAddress();
154
- const shortAddress = walletAddress.substring(0, 6) + '...' + walletAddress.substring(walletAddress.length - 4);
155
- console.log(`${index + 1}. ${shortAddress}: ${walletInfo.balance} ${inputToken.symbol}`);
141
+ allWallets.push({
142
+ wallet,
143
+ balance: tokenBalance
156
144
  });
157
- throw new Error(error_msg);
158
145
  }
159
- console.log('availableWallets', availableWallets.map(w => w.wallet.getPublicKey().toSuiAddress()));
160
- const wallet_last_used = yield this.redisClient.hgetall('sui:wallet:last_used');
161
- for (const availableWallet of availableWallets) {
162
- const walletAddress = availableWallet.wallet.getPublicKey().toSuiAddress();
163
- const lastUsedData = wallet_last_used === null || wallet_last_used === void 0 ? void 0 : wallet_last_used[walletAddress];
164
- if (lastUsedData) {
165
- try {
166
- const lastUsedInfo = JSON.parse(lastUsedData);
167
- availableWallet.lastUsedAt = lastUsedInfo.lastUsedAt;
168
- }
169
- catch (error) {
170
- console.warn(`解析钱包最后使用时间失败: ${walletAddress}`, error);
171
- }
146
+ catch (error) {
147
+ console.warn(`处理钱包资产时出错: ${walletAddress}`, error);
148
+ }
149
+ }
150
+ if (availableWallets.length === 0) {
151
+ let error_msg = `all wallets are insufficient, required: ${requiredAmount} ${inputToken.symbol}`;
152
+ (0, dist_1.log_warn)(error_msg);
153
+ allWallets.forEach((walletInfo, index) => {
154
+ const walletAddress = walletInfo.wallet.getPublicKey().toSuiAddress();
155
+ const shortAddress = walletAddress.substring(0, 6) + '...' + walletAddress.substring(walletAddress.length - 4);
156
+ console.log(`${index + 1}. ${shortAddress}: ${walletInfo.balance} ${inputToken.symbol}`);
157
+ });
158
+ throw new Error(error_msg);
159
+ }
160
+ console.log('availableWallets', availableWallets.map(w => w.wallet.getPublicKey().toSuiAddress()));
161
+ const wallet_last_used = await this.redisClient.hgetall('sui:wallet:last_used');
162
+ for (const availableWallet of availableWallets) {
163
+ const walletAddress = availableWallet.wallet.getPublicKey().toSuiAddress();
164
+ const lastUsedData = wallet_last_used?.[walletAddress];
165
+ if (lastUsedData) {
166
+ try {
167
+ const lastUsedInfo = JSON.parse(lastUsedData);
168
+ availableWallet.lastUsedAt = lastUsedInfo.lastUsedAt;
172
169
  }
173
- else {
174
- yield this.redisClient.hsetValue('sui:wallet:last_used', walletAddress, JSON.stringify({
175
- lastUsedAt: 0,
176
- lastUsedTime: new Date(0).toISOString()
177
- }), 24 * 60 * 60);
178
- availableWallet.lastUsedAt = 0;
170
+ catch (error) {
171
+ console.warn(`解析钱包最后使用时间失败: ${walletAddress}`, error);
179
172
  }
180
173
  }
181
- let selectedWallet;
182
- let selectionStrategy;
183
- if (availableWallets.length === 1) {
184
- selectedWallet = availableWallets[0].wallet;
185
- selectionStrategy = 'OnlyOne';
186
- }
187
174
  else {
188
- const hasUsageHistory = wallet_last_used && Object.keys(wallet_last_used).length > 0;
189
- if (hasUsageHistory) {
190
- availableWallets.sort((a, b) => {
191
- const aTime = a.lastUsedAt || 0;
192
- const bTime = b.lastUsedAt || 0;
193
- return aTime - bTime;
194
- });
195
- selectedWallet = availableWallets[0].wallet;
196
- selectionStrategy = 'MaxLastUsed';
197
- }
198
- else {
199
- availableWallets.sort((a, b) => {
200
- const aBalance = new decimal_js_1.default(a.balance);
201
- const bBalance = new decimal_js_1.default(b.balance);
202
- return bBalance.cmp(aBalance);
203
- });
204
- selectedWallet = availableWallets[0].wallet;
205
- selectionStrategy = 'MaxBalance';
206
- }
175
+ await this.redisClient.hsetValue('sui:wallet:last_used', walletAddress, JSON.stringify({
176
+ lastUsedAt: 0,
177
+ lastUsedTime: new Date(0).toISOString()
178
+ }), 24 * 60 * 60);
179
+ availableWallet.lastUsedAt = 0;
207
180
  }
208
- const selectedWalletAddress = selectedWallet.getPublicKey().toSuiAddress();
209
- yield this.redisClient.hsetValue('sui:wallet:last_used', selectedWalletAddress, JSON.stringify({
210
- lastUsedAt: Date.now(),
211
- lastUsedTime: new Date().toISOString()
212
- }), 24 * 60 * 60);
213
- const selectedWalletInfo = availableWallets.find(w => w.wallet.getPublicKey().toSuiAddress() === selectedWalletAddress);
214
- (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}`);
215
- return selectedWallet;
216
181
  }
217
- catch (error) {
218
- (0, dist_1.log_error)(`choose wallet failed, error: ${error.message}`, error);
219
- throw error;
182
+ let selectedWallet;
183
+ let selectionStrategy;
184
+ if (availableWallets.length === 1) {
185
+ selectedWallet = availableWallets[0].wallet;
186
+ selectionStrategy = 'OnlyOne';
220
187
  }
221
- finally {
222
- yield this.redisClient.releaseLock(lockKey, lockValue);
188
+ else {
189
+ const hasUsageHistory = wallet_last_used && Object.keys(wallet_last_used).length > 0;
190
+ if (hasUsageHistory) {
191
+ availableWallets.sort((a, b) => {
192
+ const aTime = a.lastUsedAt || 0;
193
+ const bTime = b.lastUsedAt || 0;
194
+ return aTime - bTime;
195
+ });
196
+ selectedWallet = availableWallets[0].wallet;
197
+ selectionStrategy = 'MaxLastUsed';
198
+ }
199
+ else {
200
+ availableWallets.sort((a, b) => {
201
+ const aBalance = new decimal_js_1.default(a.balance);
202
+ const bBalance = new decimal_js_1.default(b.balance);
203
+ return bBalance.cmp(aBalance);
204
+ });
205
+ selectedWallet = availableWallets[0].wallet;
206
+ selectionStrategy = 'MaxBalance';
207
+ }
223
208
  }
224
- });
209
+ const selectedWalletAddress = selectedWallet.getPublicKey().toSuiAddress();
210
+ await this.redisClient.hsetValue('sui:wallet:last_used', selectedWalletAddress, JSON.stringify({
211
+ lastUsedAt: Date.now(),
212
+ lastUsedTime: new Date().toISOString()
213
+ }), 24 * 60 * 60);
214
+ const selectedWalletInfo = availableWallets.find(w => w.wallet.getPublicKey().toSuiAddress() === selectedWalletAddress);
215
+ (0, dist_1.log_info)(`Choose wallet: ${selectionStrategy} -> ${selectedWalletAddress}, balance: ${selectedWalletInfo?.balance} ${inputToken.symbol}, required: ${requiredAmount} ${inputToken.symbol}`);
216
+ return selectedWallet;
217
+ }
218
+ catch (error) {
219
+ (0, dist_1.log_error)(`choose wallet failed, error: ${error.message}`, error);
220
+ throw error;
221
+ }
222
+ finally {
223
+ await this.redisClient.releaseLock(lockKey, lockValue);
224
+ }
225
225
  }
226
226
  determineInputOutputTokens(order_msg, pool_info) {
227
227
  const { aToB } = order_msg;
@@ -245,19 +245,19 @@ class AbstractSuiDexTradePlus extends dist_1.AbastrcatTrade {
245
245
  let { ask, bid } = price_msg;
246
246
  const { aToB, amount: uiAmount, price: cex_order_price } = order_msg;
247
247
  let { inputToken, outputToken } = (0, dist_1.get_input_out_token)(pool_info, aToB);
248
- let amountIn = new decimal_js_1.default(uiAmount).mul(Math.pow(10, inputToken.decimals));
248
+ let amountIn = new decimal_js_1.default(uiAmount).mul(10 ** inputToken.decimals);
249
249
  let slippage = slippage_bps / 10000;
250
250
  let price;
251
251
  let amountOut;
252
252
  let amountOutMin;
253
253
  if (aToB) {
254
- price = cex_order_price !== null && cex_order_price !== void 0 ? cex_order_price : bid.price;
255
- amountOut = new decimal_js_1.default(uiAmount).mul(price).mul(Math.pow(10, outputToken.decimals));
254
+ price = cex_order_price ?? bid.price;
255
+ amountOut = new decimal_js_1.default(uiAmount).mul(price).mul(10 ** outputToken.decimals);
256
256
  amountOutMin = amountOut.mul(1 - slippage);
257
257
  }
258
258
  else {
259
- price = cex_order_price !== null && cex_order_price !== void 0 ? cex_order_price : ask.price;
260
- amountOut = new decimal_js_1.default(uiAmount).div(price).mul(Math.pow(10, outputToken.decimals));
259
+ price = cex_order_price ?? ask.price;
260
+ amountOut = new decimal_js_1.default(uiAmount).div(price).mul(10 ** outputToken.decimals);
261
261
  amountOutMin = amountOut.mul(1 - slippage);
262
262
  }
263
263
  let quote_result = {
@@ -272,53 +272,49 @@ class AbstractSuiDexTradePlus extends dist_1.AbastrcatTrade {
272
272
  };
273
273
  return quote_result;
274
274
  }
275
- getWalletAssetsFromRedis(walletAddress) {
276
- return __awaiter(this, void 0, void 0, function* () {
277
- try {
278
- const redisClient = this.appConfig.arb_cache.redis_cmd.redis_client;
279
- const walletAssetsJson = yield redisClient.HGET('sui:wallet:assets', walletAddress);
280
- if (!walletAssetsJson) {
281
- return null;
282
- }
283
- return JSON.parse(walletAssetsJson);
284
- }
285
- catch (error) {
286
- (0, dist_1.log_error)(`从Redis获取钱包资产信息失败`, error);
287
- throw error;
275
+ async getWalletAssetsFromRedis(walletAddress) {
276
+ try {
277
+ const redisClient = this.appConfig.arb_cache.redis_cmd.redis_client;
278
+ const walletAssetsJson = await redisClient.HGET('sui:wallet:assets', walletAddress);
279
+ if (!walletAssetsJson) {
280
+ return null;
288
281
  }
289
- });
282
+ return JSON.parse(walletAssetsJson);
283
+ }
284
+ catch (error) {
285
+ (0, dist_1.log_error)(`从Redis获取钱包资产信息失败`, error);
286
+ throw error;
287
+ }
290
288
  }
291
- getObjectInfo(objectId) {
292
- return __awaiter(this, void 0, void 0, function* () {
293
- try {
294
- let startTime = Date.now();
295
- const objectResponse = yield this.grpcClient.ledgerService.getObject(objectId, [
296
- 'object_id',
297
- 'version',
298
- 'digest',
299
- 'owner',
300
- ]);
301
- let objectInfo = null;
302
- if (objectResponse.object) {
303
- objectInfo = {
304
- objectId: objectId,
305
- version: objectResponse.object.version,
306
- digest: objectResponse.object.digest,
307
- initialSharedVersion: objectResponse.object.owner.version
308
- };
309
- }
310
- (0, dist_1.log_info)(`get object info success, cost: ${Date.now() - startTime} ms`, objectInfo);
311
- return objectInfo;
312
- }
313
- catch (error) {
314
- (0, dist_1.log_error)(`get object info failed, object_id=${objectId}`, error);
315
- return null;
289
+ async getObjectInfo(objectId) {
290
+ try {
291
+ let startTime = Date.now();
292
+ const objectResponse = await this.grpcClient.ledgerService.getObject(objectId, [
293
+ 'object_id',
294
+ 'version',
295
+ 'digest',
296
+ 'owner',
297
+ ]);
298
+ let objectInfo = null;
299
+ if (objectResponse.object) {
300
+ objectInfo = {
301
+ objectId: objectId,
302
+ version: objectResponse.object.version,
303
+ digest: objectResponse.object.digest,
304
+ initialSharedVersion: objectResponse.object.owner.version
305
+ };
316
306
  }
317
- });
307
+ (0, dist_1.log_info)(`get object info success, cost: ${Date.now() - startTime} ms`, objectInfo);
308
+ return objectInfo;
309
+ }
310
+ catch (error) {
311
+ (0, dist_1.log_error)(`get object info failed, object_id=${objectId}`, error);
312
+ return null;
313
+ }
318
314
  }
319
315
  compareBigIntBalance(a, b) {
320
- const balanceA = BigInt((a === null || a === void 0 ? void 0 : a.balance) || '0');
321
- const balanceB = BigInt((b === null || b === void 0 ? void 0 : b.balance) || '0');
316
+ const balanceA = BigInt(a?.balance || '0');
317
+ const balanceB = BigInt(b?.balance || '0');
322
318
  if (balanceA > balanceB)
323
319
  return -1;
324
320
  if (balanceA < balanceB)
@@ -343,18 +339,42 @@ class AbstractSuiDexTradePlus extends dist_1.AbastrcatTrade {
343
339
  tx.mergeCoins(primaryCoin, other_objects);
344
340
  (0, dist_1.log_info)(`✅ ${tokenSymbol} 进行对象合并,涉及 ${other_objects.length} 个对象`);
345
341
  }
346
- try_refresh_wallet_objects(wallet_1, txid_1, context_1) {
347
- return __awaiter(this, arguments, void 0, function* (wallet, txid, context, initial_delay_ms = 0, try_times = 5, try_delay_ms = 300) {
348
- for (let i = 0; i < try_times; i++) {
349
- let delay_ms = initial_delay_ms + i * try_delay_ms;
350
- setTimeout(() => {
351
- let group_id = this.appConfig.trade_runtime.group.id;
352
- let coin_types = [context.pool_info.tokenA.address, context.pool_info.tokenB.address];
353
- this.appConfig.arb_cache.redis_event_publisher.publish_wallet_raw_tx_event(group_id, wallet, { group_id, wallet, txid, coin_types, remark: `PRE_REFRESH_OBJECTS_${i}` });
354
- }, delay_ms);
355
- (0, dist_1.log_info)(`try_refresh_wallet_objects, txid=${txid}, i=${i}, delay_ms=${delay_ms}ms`);
356
- }
342
+ async try_refresh_wallet_objects(wallet, txid, context, initial_delay_ms = 0, try_times = 5, try_delay_ms = 300) {
343
+ for (let i = 0; i < try_times; i++) {
344
+ let delay_ms = initial_delay_ms + i * try_delay_ms;
345
+ setTimeout(() => {
346
+ let group_id = this.appConfig.trade_runtime.group.id;
347
+ let coin_types = [context.pool_info.tokenA.address, context.pool_info.tokenB.address];
348
+ this.appConfig.arb_cache.redis_event_publisher.publish_wallet_raw_tx_event(group_id, wallet, { group_id, wallet, txid, coin_types, remark: `PRE_REFRESH_OBJECTS_${i}` });
349
+ }, delay_ms);
350
+ (0, dist_1.log_info)(`try_refresh_wallet_objects, txid=${txid}, i=${i}, delay_ms=${delay_ms}ms`);
351
+ }
352
+ }
353
+ async execute(context, _retryCount) {
354
+ const q = this.local_calculate_output_amt(context);
355
+ const { pool_info } = context;
356
+ const coinTypeA = (0, index_1.normalizeSuiTokenAddress)(pool_info.tokenA.address);
357
+ const coinTypeB = (0, index_1.normalizeSuiTokenAddress)(pool_info.tokenB.address);
358
+ const inAddr = (0, index_1.normalizeSuiTokenAddress)(q.inputToken.address);
359
+ const a2b = inAddr === coinTypeA;
360
+ const req = {
361
+ dexId: (pool_info.dex_id || this.appConfig.trade_runtime.dex_id),
362
+ poolId: pool_info.pool_address,
363
+ coinTypeA,
364
+ coinTypeB,
365
+ a2b,
366
+ amountIn: BigInt(q.amountIn),
367
+ minOut: BigInt(q.amountOutMin),
368
+ sqrtPriceLimit: 0n,
369
+ };
370
+ (0, dist_1.log_info)(`[trade] 转发 swap 给集中执行器`, {
371
+ dex_id: req.dexId, pair: pool_info.pair, a2b, amountIn: req.amountIn.toString(), minOut: req.minOut.toString(),
357
372
  });
373
+ const res = await this.executorClient.requestSwap(req);
374
+ if (!res.submitted) {
375
+ throw new Error(`集中执行器提交失败: ${res.error}`);
376
+ }
377
+ return res.digest;
358
378
  }
359
379
  }
360
380
  exports.AbstractSuiDexTradePlus = AbstractSuiDexTradePlus;