@clonegod/ttd-sui-common 1.0.91 → 1.0.93

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.
@@ -8,8 +8,8 @@ export declare class SimpleRedisClient {
8
8
  constructor(lock_prefix: string);
9
9
  getRedisClient(): Promise<RedisClientType>;
10
10
  private getLockKey;
11
- private acquireLock;
12
- private releaseLock;
11
+ acquireLock(lock_key: string, lock_value: string, expireSeconds?: number): Promise<boolean>;
12
+ releaseLock(lock_key: string, lock_value: string): Promise<boolean>;
13
13
  withLock<T>(lock_identifier: string, callback: () => Promise<T>, release_lock_delay_ms?: number): Promise<T>;
14
14
  getValue(key: string): Promise<string>;
15
15
  setValue(key: string, value: string, expireSeconds: number): Promise<any>;
@@ -82,118 +82,145 @@ class AbstractSuiDexTradePlus extends dist_1.AbastrcatTrade {
82
82
  if (this.getWalletMode() === 'single') {
83
83
  return this.getSingleWallet();
84
84
  }
85
- const { inputToken } = this.determineInputOutputTokens(context.order_msg, context.pool_info);
86
- console.log('inputToken', inputToken);
87
- const requiredAmount = new decimal_js_1.default(context.order_msg.amount);
88
- const wallet_assets = yield this.redisClient.hgetall('sui:wallet:assets');
89
- if (!wallet_assets || Object.keys(wallet_assets).length === 0) {
90
- throw new Error('没有找到钱包资产信息,请确保钱包监控服务正在运行');
91
- }
92
- const wallet_assets_map = {};
93
- for (const [walletAddress, assetsJson] of Object.entries(wallet_assets)) {
94
- try {
95
- wallet_assets_map[walletAddress] = JSON.parse(assetsJson);
96
- }
97
- catch (error) {
98
- console.warn(`解析钱包资产数据失败: ${walletAddress}`, error);
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, 200);
94
+ if (lockAcquired) {
95
+ break;
99
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`);
100
101
  }
101
- const availableWallets = [];
102
- const allWallets = [];
103
- for (const [walletAddress, assets] of Object.entries(wallet_assets_map)) {
104
- try {
105
- const wallet = (_a = this.group_wallets) === null || _a === void 0 ? void 0 : _a.find(w => w.getPublicKey().toSuiAddress().toLowerCase() === walletAddress.toLowerCase());
106
- if (!wallet) {
107
- continue;
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('没有找到钱包资产信息,请确保钱包监控服务正在运行');
110
+ }
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);
108
115
  }
109
- 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));
110
- let tokenBalance = (tokenAsset === null || tokenAsset === void 0 ? void 0 : tokenAsset.balance) || '0';
111
- const balanceDecimal = new decimal_js_1.default(tokenBalance);
112
- if (balanceDecimal.gte(requiredAmount)) {
113
- availableWallets.push({
116
+ catch (error) {
117
+ console.warn(`解析钱包资产数据失败: ${walletAddress}`, error);
118
+ }
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({
114
141
  wallet,
115
142
  balance: tokenBalance
116
143
  });
117
144
  }
118
- else {
119
- console.log(`钱包 ${walletAddress} 余额不足: ${tokenBalance} ${inputToken.symbol} < ${requiredAmount} ${inputToken.symbol}`);
145
+ catch (error) {
146
+ console.warn(`处理钱包资产时出错: ${walletAddress}`, error);
120
147
  }
121
- allWallets.push({
122
- wallet,
123
- balance: tokenBalance
124
- });
125
148
  }
126
- catch (error) {
127
- console.warn(`处理钱包资产时出错: ${walletAddress}`, error);
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}`);
156
+ });
157
+ throw new Error(error_msg);
128
158
  }
129
- }
130
- if (availableWallets.length === 0) {
131
- let error_msg = `all wallets are insufficient, required: ${requiredAmount} ${inputToken.symbol}`;
132
- (0, dist_1.log_warn)(error_msg);
133
- allWallets.forEach((walletInfo, index) => {
134
- const walletAddress = walletInfo.wallet.getPublicKey().toSuiAddress();
135
- const shortAddress = walletAddress.substring(0, 6) + '...' + walletAddress.substring(walletAddress.length - 4);
136
- console.log(`${index + 1}. ${shortAddress}: ${walletInfo.balance} ${inputToken.symbol}`);
137
- });
138
- throw new Error(error_msg);
139
- }
140
- console.log('availableWallets', availableWallets.map(w => w.wallet.getPublicKey().toSuiAddress()));
141
- const wallet_last_used = yield this.redisClient.hgetall('sui:wallet:last_used');
142
- for (const availableWallet of availableWallets) {
143
- const walletAddress = availableWallet.wallet.getPublicKey().toSuiAddress();
144
- const lastUsedData = wallet_last_used === null || wallet_last_used === void 0 ? void 0 : wallet_last_used[walletAddress];
145
- if (lastUsedData) {
146
- try {
147
- const lastUsedInfo = JSON.parse(lastUsedData);
148
- availableWallet.lastUsedAt = lastUsedInfo.lastUsedAt;
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
+ }
149
172
  }
150
- catch (error) {
151
- console.warn(`解析钱包最后使用时间失败: ${walletAddress}`, error);
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;
152
179
  }
153
180
  }
154
- else {
155
- yield this.redisClient.hsetValue('sui:wallet:last_used', walletAddress, JSON.stringify({
156
- lastUsedAt: 0,
157
- lastUsedTime: new Date(0).toISOString()
158
- }), 24 * 60 * 60);
159
- availableWallet.lastUsedAt = 0;
160
- }
161
- }
162
- let selectedWallet;
163
- let selectionStrategy;
164
- if (availableWallets.length === 1) {
165
- selectedWallet = availableWallets[0].wallet;
166
- selectionStrategy = 'OnlyOne';
167
- }
168
- else {
169
- const hasUsageHistory = wallet_last_used && Object.keys(wallet_last_used).length > 0;
170
- if (hasUsageHistory) {
171
- availableWallets.sort((a, b) => {
172
- const aTime = a.lastUsedAt || 0;
173
- const bTime = b.lastUsedAt || 0;
174
- return aTime - bTime;
175
- });
181
+ let selectedWallet;
182
+ let selectionStrategy;
183
+ if (availableWallets.length === 1) {
176
184
  selectedWallet = availableWallets[0].wallet;
177
- selectionStrategy = 'MaxLastUsed';
185
+ selectionStrategy = 'OnlyOne';
178
186
  }
179
187
  else {
180
- availableWallets.sort((a, b) => {
181
- const aBalance = new decimal_js_1.default(a.balance);
182
- const bBalance = new decimal_js_1.default(b.balance);
183
- return bBalance.cmp(aBalance);
184
- });
185
- selectedWallet = availableWallets[0].wallet;
186
- selectionStrategy = 'MaxBalance';
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
+ }
187
207
  }
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
+ }
217
+ catch (error) {
218
+ (0, dist_1.log_error)(`choose wallet failed, error: ${error.message}`, error);
219
+ throw error;
220
+ }
221
+ finally {
222
+ yield this.redisClient.releaseLock(lockKey, lockValue);
188
223
  }
189
- const selectedWalletAddress = selectedWallet.getPublicKey().toSuiAddress();
190
- yield this.redisClient.hsetValue('sui:wallet:last_used', selectedWalletAddress, JSON.stringify({
191
- lastUsedAt: Date.now(),
192
- lastUsedTime: new Date().toISOString()
193
- }), 24 * 60 * 60);
194
- const selectedWalletInfo = availableWallets.find(w => w.wallet.getPublicKey().toSuiAddress() === selectedWalletAddress);
195
- (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}`);
196
- return selectedWallet;
197
224
  });
198
225
  }
199
226
  determineInputOutputTokens(order_msg, pool_info) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clonegod/ttd-sui-common",
3
- "version": "1.0.91",
3
+ "version": "1.0.93",
4
4
  "description": "Sui common library",
5
5
  "license": "UNLICENSED",
6
6
  "main": "dist/index.js",