polycopy 0.2.0 → 0.2.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/dist/index.js +156 -235
- package/package.json +1 -3
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ const accounts = require("viem/accounts");
|
|
|
11
11
|
const chains = require("viem/chains");
|
|
12
12
|
const builderRelayerClient = require("@polymarket/builder-relayer-client");
|
|
13
13
|
const setPromiseInterval = require("set-promise-interval");
|
|
14
|
+
const lodash = require("lodash");
|
|
14
15
|
const child_process = require("child_process");
|
|
15
16
|
const fs = require("fs");
|
|
16
17
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
@@ -578,6 +579,12 @@ class TelegramService {
|
|
|
578
579
|
async stop() {
|
|
579
580
|
await this.ensureListener().stop();
|
|
580
581
|
}
|
|
582
|
+
/**
|
|
583
|
+
* 发送普通通知
|
|
584
|
+
*/
|
|
585
|
+
async info(message, details) {
|
|
586
|
+
await this.send(`${message}`, details);
|
|
587
|
+
}
|
|
581
588
|
/**
|
|
582
589
|
* 发送错误通知
|
|
583
590
|
*/
|
|
@@ -1071,103 +1078,48 @@ class OrderWatcher {
|
|
|
1071
1078
|
}
|
|
1072
1079
|
}
|
|
1073
1080
|
const DATA_API_HOST = "https://data-api.polymarket.com";
|
|
1074
|
-
const
|
|
1075
|
-
const
|
|
1081
|
+
const AUTO_REDEEM_INTERVAL = 5 * 60 * 1e3;
|
|
1082
|
+
const MAX_BATCH_SIZE = 5;
|
|
1076
1083
|
const MAX_MATCH_TIMES = 3;
|
|
1077
1084
|
class Redeemer {
|
|
1078
1085
|
// conditionId -> RedeemRecord
|
|
1079
1086
|
records = /* @__PURE__ */ new Map();
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
this.scheduler = scheduler;
|
|
1096
|
-
}
|
|
1097
|
-
/**
|
|
1098
|
-
* 启动 Redeemer
|
|
1099
|
-
* @param redeemFn 执行 Redeem 的函数(返回交易哈希)
|
|
1100
|
-
* @param funderAddress Polymarket 账户地址(用于查询仓位)
|
|
1101
|
-
* @param onRedeemSuccess Redeem 成功后的回调(用于更新余额缓存)
|
|
1102
|
-
*/
|
|
1103
|
-
start(redeemFn, funderAddress, onRedeemSuccess) {
|
|
1104
|
-
if (this.state !== "stopped") {
|
|
1105
|
-
return;
|
|
1106
|
-
}
|
|
1107
|
-
this.redeemFn = redeemFn;
|
|
1108
|
-
const envBatchSize = Number(process.env.POLYCOPY_REDEEM_BATCH_SIZE || "");
|
|
1109
|
-
if (!Number.isNaN(envBatchSize) && envBatchSize > 0) {
|
|
1110
|
-
this.batchSize = Math.floor(envBatchSize);
|
|
1111
|
-
}
|
|
1112
|
-
this.funderAddress = funderAddress;
|
|
1113
|
-
this.onRedeemSuccess = onRedeemSuccess || null;
|
|
1114
|
-
this.state = "running";
|
|
1115
|
-
logger.success("自动 redeem 已启动");
|
|
1116
|
-
this.startInterval();
|
|
1117
|
-
}
|
|
1118
|
-
/**
|
|
1119
|
-
* 启动定时任务(仅在 running 状态生效)
|
|
1120
|
-
*/
|
|
1121
|
-
startInterval() {
|
|
1122
|
-
if (this.state !== "running" || this.intervalId !== void 0) {
|
|
1123
|
-
return;
|
|
1124
|
-
}
|
|
1125
|
-
this.intervalId = this.scheduler.setInterval(async () => {
|
|
1126
|
-
await this.runOnce();
|
|
1127
|
-
}, BASE_INTERVAL);
|
|
1128
|
-
}
|
|
1129
|
-
/**
|
|
1130
|
-
* 暂停定时任务,延迟后重启(用于 429 限流)
|
|
1131
|
-
*/
|
|
1132
|
-
pauseAndRestart(delayMs) {
|
|
1133
|
-
if (this.intervalId !== void 0) {
|
|
1134
|
-
this.scheduler.clearInterval(this.intervalId);
|
|
1135
|
-
this.intervalId = void 0;
|
|
1136
|
-
}
|
|
1137
|
-
if (this.delayTimeoutId) {
|
|
1138
|
-
this.scheduler.clearTimeout(this.delayTimeoutId);
|
|
1139
|
-
this.delayTimeoutId = void 0;
|
|
1140
|
-
}
|
|
1141
|
-
this.state = "paused";
|
|
1142
|
-
this.delayTimeoutId = this.scheduler.setTimeout(() => {
|
|
1143
|
-
this.delayTimeoutId = void 0;
|
|
1144
|
-
if (this.state === "paused") {
|
|
1145
|
-
this.state = "running";
|
|
1146
|
-
this.startInterval();
|
|
1147
|
-
}
|
|
1148
|
-
}, delayMs);
|
|
1087
|
+
running = false;
|
|
1088
|
+
mainTimer;
|
|
1089
|
+
restartTimer;
|
|
1090
|
+
options;
|
|
1091
|
+
constructor(options) {
|
|
1092
|
+
this.options = options;
|
|
1093
|
+
}
|
|
1094
|
+
start(restart) {
|
|
1095
|
+
if (this.running) return;
|
|
1096
|
+
this.running = true;
|
|
1097
|
+
this.mainTimer = setPromiseInterval__default.default(
|
|
1098
|
+
this.autoRedeem.bind(this),
|
|
1099
|
+
AUTO_REDEEM_INTERVAL
|
|
1100
|
+
);
|
|
1101
|
+
logger.success(restart ? "自动 redeem 已重启" : "自动 redeem 已启动");
|
|
1149
1102
|
}
|
|
1150
|
-
/**
|
|
1151
|
-
* 停止 Redeemer
|
|
1152
|
-
*/
|
|
1153
1103
|
stop() {
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
}
|
|
1158
|
-
if (this.delayTimeoutId) {
|
|
1159
|
-
this.scheduler.clearTimeout(this.delayTimeoutId);
|
|
1160
|
-
this.delayTimeoutId = void 0;
|
|
1161
|
-
}
|
|
1162
|
-
this.state = "stopped";
|
|
1104
|
+
setPromiseInterval.clearPromiseInterval(this.mainTimer);
|
|
1105
|
+
clearTimeout(this.restartTimer);
|
|
1106
|
+
this.running = false;
|
|
1163
1107
|
logger.info("自动 redeem 已停止");
|
|
1164
1108
|
}
|
|
1109
|
+
restart(delayMs) {
|
|
1110
|
+
if (!this.running) return;
|
|
1111
|
+
this.stop();
|
|
1112
|
+
this.restartTimer = setTimeout(() => {
|
|
1113
|
+
this.start(true);
|
|
1114
|
+
telegramService.info("自动 redeem 已重启");
|
|
1115
|
+
}, delayMs);
|
|
1116
|
+
}
|
|
1165
1117
|
/**
|
|
1166
1118
|
* 获取可 Redeem 的仓位
|
|
1167
1119
|
*/
|
|
1168
1120
|
async fetchRedeemablePositions() {
|
|
1169
1121
|
const url = new URL(`${DATA_API_HOST}/positions`);
|
|
1170
|
-
url.searchParams.set("user", this.funderAddress);
|
|
1122
|
+
url.searchParams.set("user", this.options.funderAddress);
|
|
1171
1123
|
url.searchParams.set("redeemable", "true");
|
|
1172
1124
|
url.searchParams.set("sizeThreshold", ".1");
|
|
1173
1125
|
url.searchParams.set("sortBy", "CURRENT");
|
|
@@ -1197,63 +1149,35 @@ class Redeemer {
|
|
|
1197
1149
|
}
|
|
1198
1150
|
return positions;
|
|
1199
1151
|
}
|
|
1152
|
+
testRequestLimit(errorMsg) {
|
|
1153
|
+
if (errorMsg.includes("429") || errorMsg.includes("Too Many Requests")) {
|
|
1154
|
+
const match = errorMsg.match(/resets in (\d+) seconds/);
|
|
1155
|
+
return match ? parseInt(match[1]) : 0;
|
|
1156
|
+
}
|
|
1157
|
+
return 0;
|
|
1158
|
+
}
|
|
1159
|
+
toMessages(records) {
|
|
1160
|
+
return records.map(
|
|
1161
|
+
({ position, matchedCount, failedCount }) => ` - ${position.slug} ${position.outcome}: ${position.currentValue} USDC (matched: ${matchedCount} failed: ${failedCount})`
|
|
1162
|
+
);
|
|
1163
|
+
}
|
|
1200
1164
|
/**
|
|
1201
1165
|
* 执行一轮 Redeem
|
|
1202
1166
|
*/
|
|
1203
|
-
async
|
|
1204
|
-
|
|
1205
|
-
return;
|
|
1206
|
-
}
|
|
1207
|
-
let positions;
|
|
1167
|
+
async autoRedeem() {
|
|
1168
|
+
let redeemablePositions;
|
|
1208
1169
|
try {
|
|
1209
|
-
|
|
1170
|
+
redeemablePositions = await this.fetchRedeemablePositions();
|
|
1210
1171
|
} catch (error) {
|
|
1211
1172
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
1212
|
-
|
|
1213
|
-
const resetSeconds = this.parseResetSeconds(errorMsg);
|
|
1214
|
-
logger.warning(`获取仓位限流,${resetSeconds} 秒后重试`);
|
|
1215
|
-
telegramService.warning(
|
|
1216
|
-
"API 限流",
|
|
1217
|
-
`获取仓位限流,${resetSeconds} 秒后重试`
|
|
1218
|
-
);
|
|
1219
|
-
this.pauseAndRestart((resetSeconds + 60) * 1e3);
|
|
1220
|
-
return;
|
|
1221
|
-
}
|
|
1222
|
-
logger.error(`获取仓位失败: ${errorMsg}`);
|
|
1173
|
+
logger.error(`自动 redeem: 获取仓位失败: ${errorMsg}`);
|
|
1223
1174
|
return;
|
|
1224
1175
|
}
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
const
|
|
1228
|
-
|
|
1229
|
-
const
|
|
1230
|
-
if (!shouldContinue) {
|
|
1231
|
-
return;
|
|
1232
|
-
}
|
|
1233
|
-
const successItems = this.collectSuccessRecords(currentIds);
|
|
1234
|
-
if (successItems.length > 0) {
|
|
1235
|
-
const successTitle = `自动 redeem: 成功 ${successItems.length} 个`;
|
|
1236
|
-
const successLines = this.logPositions(successTitle, successItems);
|
|
1237
|
-
telegramService.success(successTitle, successLines.join("\n"));
|
|
1238
|
-
this.onRedeemSuccess?.();
|
|
1239
|
-
}
|
|
1240
|
-
logger.info(`redeem 状态: ${this.records.size} 个待确认`);
|
|
1241
|
-
}
|
|
1242
|
-
logPendingPositions(positions) {
|
|
1243
|
-
const pendingRedeemablePositions = positions.filter((position) => {
|
|
1244
|
-
const record = this.records.get(position.conditionId);
|
|
1245
|
-
return !record?.success;
|
|
1246
|
-
});
|
|
1247
|
-
if (pendingRedeemablePositions.length > 0) {
|
|
1248
|
-
this.logPositions(
|
|
1249
|
-
`自动 redeem: 发现 ${pendingRedeemablePositions.length} 个可 Redeem 仓位`,
|
|
1250
|
-
pendingRedeemablePositions.map((position) => ({ position }))
|
|
1251
|
-
);
|
|
1252
|
-
logger.info(`Redeem 批量大小: ${this.batchSize}`);
|
|
1253
|
-
}
|
|
1254
|
-
}
|
|
1255
|
-
buildRecords(positions) {
|
|
1256
|
-
return positions.map((position) => {
|
|
1176
|
+
let requestLimit = 0;
|
|
1177
|
+
const pendingRedeems = [];
|
|
1178
|
+
const failedRedeems = [];
|
|
1179
|
+
const successRedeem = [];
|
|
1180
|
+
for (const position of redeemablePositions) {
|
|
1257
1181
|
let record = this.records.get(position.conditionId);
|
|
1258
1182
|
if (!record) {
|
|
1259
1183
|
record = {
|
|
@@ -1265,111 +1189,104 @@ class Redeemer {
|
|
|
1265
1189
|
this.records.set(position.conditionId, record);
|
|
1266
1190
|
}
|
|
1267
1191
|
record.position = position;
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
if (
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
}
|
|
1279
|
-
record.matchedCount++;
|
|
1280
|
-
if (record.matchedCount >= MAX_MATCH_TIMES) {
|
|
1281
|
-
logger.error(
|
|
1282
|
-
`Redeem 失败: 执行成功但仍存在 ${record.matchedCount} 次 (conditionId: ${record.position.conditionId.slice(0, 10)}...)`
|
|
1283
|
-
);
|
|
1284
|
-
telegramService.error(
|
|
1285
|
-
"Redeem 失败",
|
|
1286
|
-
`执行成功但仓位仍存在 ${record.matchedCount} 次
|
|
1287
|
-
conditionId: ${record.position.conditionId}
|
|
1288
|
-
价值: ${record.position.currentValue} USDC`
|
|
1192
|
+
if (record.success) {
|
|
1193
|
+
record.matchedCount++;
|
|
1194
|
+
if (record.matchedCount === MAX_MATCH_TIMES) {
|
|
1195
|
+
failedRedeems.push(record);
|
|
1196
|
+
}
|
|
1197
|
+
} else if (record.failedCount < MAX_MATCH_TIMES) {
|
|
1198
|
+
const insertIndex = lodash.sortedIndexBy(
|
|
1199
|
+
pendingRedeems,
|
|
1200
|
+
record,
|
|
1201
|
+
"failedCount"
|
|
1289
1202
|
);
|
|
1203
|
+
pendingRedeems.splice(insertIndex, 0, record);
|
|
1290
1204
|
}
|
|
1291
1205
|
}
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
return false;
|
|
1314
|
-
}
|
|
1315
|
-
batch.forEach((record) => {
|
|
1316
|
-
record.failedCount++;
|
|
1317
|
-
});
|
|
1318
|
-
logger.error(`Redeem 批量异常 (批量 ${batch.length}): ${errorMsg}`);
|
|
1319
|
-
batch.forEach((record) => {
|
|
1320
|
-
if (record.failedCount >= MAX_MATCH_TIMES) {
|
|
1321
|
-
telegramService.error(
|
|
1322
|
-
"Redeem 异常",
|
|
1323
|
-
`重试 ${record.failedCount} 次仍失败
|
|
1324
|
-
conditionId: ${record.position.conditionId}
|
|
1325
|
-
错误: ${errorMsg}`
|
|
1326
|
-
);
|
|
1206
|
+
const execRedeems = pendingRedeems.slice(0, MAX_BATCH_SIZE);
|
|
1207
|
+
if (execRedeems.length > 0) {
|
|
1208
|
+
try {
|
|
1209
|
+
const txHash = await this.options.redeemFn(
|
|
1210
|
+
execRedeems.map(({ position }) => position.conditionId)
|
|
1211
|
+
);
|
|
1212
|
+
logger.info(`Redeem 已执行 (批量 ${execRedeems.length}): ${txHash}`);
|
|
1213
|
+
for (const record of execRedeems) record.success = true;
|
|
1214
|
+
} catch (error) {
|
|
1215
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
1216
|
+
logger.error(
|
|
1217
|
+
`Redeem 批量异常 (批量 ${execRedeems.length}): ${errorMsg}`
|
|
1218
|
+
);
|
|
1219
|
+
requestLimit = this.testRequestLimit(errorMsg);
|
|
1220
|
+
if (requestLimit <= 0) {
|
|
1221
|
+
for (const record of execRedeems) {
|
|
1222
|
+
record.failedCount++;
|
|
1223
|
+
if (record.failedCount >= MAX_MATCH_TIMES) {
|
|
1224
|
+
failedRedeems.push(record);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1327
1227
|
}
|
|
1328
|
-
}
|
|
1228
|
+
}
|
|
1329
1229
|
}
|
|
1330
|
-
return true;
|
|
1331
|
-
}
|
|
1332
|
-
collectSuccessRecords(currentIds) {
|
|
1333
|
-
const successItems = [];
|
|
1334
1230
|
for (const [conditionId, record] of this.records.entries()) {
|
|
1335
|
-
if (!
|
|
1336
|
-
|
|
1337
|
-
position: record.position,
|
|
1338
|
-
matchedCount: record.matchedCount
|
|
1339
|
-
});
|
|
1231
|
+
if (!redeemablePositions.some((p) => p.conditionId === conditionId)) {
|
|
1232
|
+
successRedeem.push(record);
|
|
1340
1233
|
this.records.delete(conditionId);
|
|
1341
1234
|
}
|
|
1342
1235
|
}
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1236
|
+
const messages = [];
|
|
1237
|
+
if (successRedeem.length > 0) {
|
|
1238
|
+
messages.push("🟢 redeem 成功:", ...this.toMessages(successRedeem));
|
|
1239
|
+
}
|
|
1240
|
+
if (failedRedeems.length > 0) {
|
|
1241
|
+
messages.push("🔴 redeem 失败:", ...this.toMessages(failedRedeems));
|
|
1242
|
+
}
|
|
1243
|
+
if (messages.length > 0) {
|
|
1244
|
+
telegramService.info(messages.join("\n"));
|
|
1245
|
+
}
|
|
1246
|
+
const logLines = [];
|
|
1247
|
+
if (execRedeems.length > 0) {
|
|
1248
|
+
logLines.push(
|
|
1249
|
+
`redeem 本轮执行(待确认): ${execRedeems.length} 个`,
|
|
1250
|
+
...this.toMessages(execRedeems),
|
|
1251
|
+
""
|
|
1252
|
+
);
|
|
1253
|
+
}
|
|
1254
|
+
if (pendingRedeems.length > 0) {
|
|
1255
|
+
logLines.push(
|
|
1256
|
+
`redeem 本轮未执行(等待下轮): ${pendingRedeems.length} 个`,
|
|
1257
|
+
...this.toMessages(pendingRedeems),
|
|
1258
|
+
""
|
|
1259
|
+
);
|
|
1260
|
+
}
|
|
1261
|
+
logLines.push(`redeem 待确认总数: ${this.records.size} 个`, "");
|
|
1262
|
+
if (successRedeem.length > 0) {
|
|
1263
|
+
logLines.push(
|
|
1264
|
+
`🟢 redeem 成功确认: ${successRedeem.length} 个`,
|
|
1265
|
+
...this.toMessages(successRedeem),
|
|
1266
|
+
""
|
|
1267
|
+
);
|
|
1268
|
+
}
|
|
1269
|
+
if (failedRedeems.length > 0) {
|
|
1270
|
+
logLines.push(
|
|
1271
|
+
`🔴 redeem 失败已放弃(重试超限): ${failedRedeems.length} 个`,
|
|
1272
|
+
...this.toMessages(failedRedeems),
|
|
1273
|
+
""
|
|
1274
|
+
);
|
|
1275
|
+
}
|
|
1276
|
+
if (logLines.length > 0) {
|
|
1277
|
+
while (logLines.length > 0 && logLines[logLines.length - 1] === "") {
|
|
1278
|
+
logLines.pop();
|
|
1279
|
+
}
|
|
1280
|
+
logger.info(logLines.join("\n"));
|
|
1281
|
+
}
|
|
1282
|
+
if (successRedeem.length > 0) {
|
|
1283
|
+
this.options.onRedeemSuccess?.();
|
|
1284
|
+
}
|
|
1285
|
+
if (requestLimit > 0) {
|
|
1286
|
+
logger.warning(`Redeem 限流,${requestLimit} 秒后重试`);
|
|
1287
|
+
telegramService.warning("Redeem 限流", `${requestLimit} 秒后重试`);
|
|
1288
|
+
this.restart(requestLimit * 1e3);
|
|
1364
1289
|
}
|
|
1365
|
-
return lines;
|
|
1366
|
-
}
|
|
1367
|
-
/**
|
|
1368
|
-
* 解析 429 错误中的 resets in 时间
|
|
1369
|
-
*/
|
|
1370
|
-
parseResetSeconds(errorMsg) {
|
|
1371
|
-
const match = errorMsg.match(/resets in (\d+) seconds/);
|
|
1372
|
-
return match ? parseInt(match[1]) : 3600;
|
|
1373
1290
|
}
|
|
1374
1291
|
}
|
|
1375
1292
|
const POSITION_POLL_INTERVAL = 5e3;
|
|
@@ -1389,7 +1306,6 @@ class Trader {
|
|
|
1389
1306
|
this.assetFilter = new AssetFilter();
|
|
1390
1307
|
this.balanceCache = new BalanceCache();
|
|
1391
1308
|
this.orderWatcher = new OrderWatcher();
|
|
1392
|
-
this.redeemer = new Redeemer();
|
|
1393
1309
|
}
|
|
1394
1310
|
/**
|
|
1395
1311
|
* 初始化交易模块
|
|
@@ -1426,11 +1342,16 @@ class Trader {
|
|
|
1426
1342
|
if (!this.config?.polymarket?.builderCreds) {
|
|
1427
1343
|
return;
|
|
1428
1344
|
}
|
|
1429
|
-
this.redeemer
|
|
1430
|
-
this.
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1345
|
+
if (!this.redeemer) {
|
|
1346
|
+
this.redeemer = new Redeemer({
|
|
1347
|
+
funderAddress: this.config.polymarket.funderAddress,
|
|
1348
|
+
redeemFn: this.executeRedeemBatch.bind(this),
|
|
1349
|
+
onRedeemSuccess: () => {
|
|
1350
|
+
this.balanceCache.invalidate();
|
|
1351
|
+
}
|
|
1352
|
+
});
|
|
1353
|
+
this.redeemer.start();
|
|
1354
|
+
}
|
|
1434
1355
|
}
|
|
1435
1356
|
/**
|
|
1436
1357
|
* 检查是否已初始化
|
|
@@ -1645,7 +1566,7 @@ class Trader {
|
|
|
1645
1566
|
* 停止交易模块
|
|
1646
1567
|
*/
|
|
1647
1568
|
async shutdown() {
|
|
1648
|
-
this.redeemer
|
|
1569
|
+
this.redeemer?.stop();
|
|
1649
1570
|
logger.info("交易模块已停止");
|
|
1650
1571
|
}
|
|
1651
1572
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polycopy",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "polycopy test",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -13,8 +13,6 @@
|
|
|
13
13
|
"dev": "tsc --noEmit && vite build && node dist/index.js",
|
|
14
14
|
"cli": "node dist/cli.js",
|
|
15
15
|
"prepublishOnly": "npm run build",
|
|
16
|
-
"test": "HOME=$PWD node --import tsx tests/redeemer.test.ts",
|
|
17
|
-
"test:redeemer": "HOME=$PWD node --import tsx tests/redeemer.test.ts",
|
|
18
16
|
"test:log-follow": "node scripts/test-log-follow.cjs"
|
|
19
17
|
},
|
|
20
18
|
"dependencies": {
|