polycopy 0.2.8 → 0.2.9

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 (2) hide show
  1. package/dist/index.js +117 -62
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -869,24 +869,32 @@ class RelayClient extends EventEmitter__default.default {
869
869
  }
870
870
  makePostData() {
871
871
  const total = this.pendingTransactions.length;
872
- const transactions = this.pendingTransactions.sort((a, b) => a.retryNum - b.retryNum).splice(0, this.options.batchSize);
872
+ const transactions = this.pendingTransactions.sort((a, b) => a.execCount - b.execCount).splice(0, this.options.batchSize);
873
873
  if (transactions.length === 0) return null;
874
874
  const postTransactions = [];
875
- const postConditionIds = {
875
+ const postEvent = {
876
876
  redeem: [],
877
877
  merge: []
878
878
  };
879
- for (const { type, conditionId, transaction } of transactions) {
880
- postConditionIds[type].push(conditionId);
879
+ for (const { type, conditionId, execCount, transaction } of transactions) {
880
+ postEvent[type].push({ conditionId, execCount, done: false });
881
881
  postTransactions.push(transaction);
882
882
  }
883
883
  return {
884
884
  total,
885
885
  transactions,
886
- postConditionIds,
886
+ postEvent,
887
887
  postTransactions
888
888
  };
889
889
  }
890
+ logPostedEvent(type, postedEvent) {
891
+ const { success, failed } = postedEvent[type];
892
+ if (success.length + failed.length > 0) {
893
+ logger.info(
894
+ ` - ${type}: [success: ${success.length} failed: ${failed.length}(done: ${failed.filter(({ done }) => done).length})]`
895
+ );
896
+ }
897
+ }
890
898
  exec() {
891
899
  if (this.postTimeout || this.pendingTransactions.length === 0 || this.resetsTime) {
892
900
  return;
@@ -901,17 +909,17 @@ class RelayClient extends EventEmitter__default.default {
901
909
  this.postTimeout = setTimeout(() => {
902
910
  const postData = this.makePostData();
903
911
  if (!postData) return;
904
- const { total, transactions, postTransactions, postConditionIds } = postData;
912
+ const { total, transactions, postTransactions, postEvent } = postData;
905
913
  logger.info(
906
914
  "RelayClient",
907
915
  "post transactions:",
908
916
  `${transactions.length}/${total}`
909
917
  );
910
918
  logger.info(` - pending: ${this.pendingTransactions.length}`);
911
- this.emit("post", postConditionIds);
919
+ this.emit("post", postEvent);
912
920
  const onPosted = (txHash, error) => {
913
921
  this.lastPostTime = Date.now();
914
- const postedRet = {
922
+ const postedEvent = {
915
923
  txHash,
916
924
  error,
917
925
  redeem: {
@@ -925,30 +933,37 @@ class RelayClient extends EventEmitter__default.default {
925
933
  };
926
934
  const resolveTx = txHash ? (pt) => {
927
935
  pt.resolve(txHash);
928
- const success = postedRet[pt.type].success;
929
- success.push(pt.conditionId);
936
+ const success = postedEvent[pt.type].success;
937
+ success.push({
938
+ conditionId: pt.conditionId,
939
+ execCount: pt.execCount,
940
+ done: true
941
+ });
930
942
  } : (pt) => {
931
- if (pt.retryNum >= this.options.maxRetry) {
943
+ let done;
944
+ if (pt.execCount >= this.options.maxRetry) {
932
945
  pt.reject(error);
933
- const failed = postedRet[pt.type].failed;
934
- failed.push(pt.conditionId);
946
+ done = true;
935
947
  } else {
936
948
  this.pendingTransactions.push(pt);
949
+ done = false;
937
950
  }
951
+ const failed = postedEvent[pt.type].failed;
952
+ failed.push({
953
+ conditionId: pt.conditionId,
954
+ execCount: pt.execCount,
955
+ done
956
+ });
938
957
  };
939
958
  for (const pt of transactions) {
940
- pt.retryNum++;
959
+ pt.execCount++;
941
960
  resolveTx(pt);
942
961
  }
943
962
  logger.info("RelayClient", "post transactions done:");
944
- logger.info(
945
- ` - redeem: [success: ${postedRet.redeem.success.length} failed: ${postedRet.redeem.failed.length}]`
946
- );
947
- logger.info(
948
- ` - merge: [success: ${postedRet.merge.success.length} failed: ${postedRet.merge.failed.length}]`
949
- );
963
+ this.logPostedEvent("redeem", postedEvent);
964
+ this.logPostedEvent("merge", postedEvent);
950
965
  logger.info(` - pending: ${this.pendingTransactions.length}`);
951
- this.emit("posted", postedRet);
966
+ this.emit("posted", postedEvent);
952
967
  };
953
968
  this.post(postTransactions).then((txHash) => onPosted(txHash)).catch((e) => {
954
969
  const requestLimit = this.testRequestLimit(e);
@@ -1051,7 +1066,7 @@ class RelayClient extends EventEmitter__default.default {
1051
1066
  type,
1052
1067
  conditionId,
1053
1068
  transaction,
1054
- retryNum: 0,
1069
+ execCount: 0,
1055
1070
  reject,
1056
1071
  resolve
1057
1072
  });
@@ -1261,11 +1276,12 @@ function listenEvent(e, eventName, callback) {
1261
1276
  }
1262
1277
  const DATA_API_HOST = "https://data-api.polymarket.com";
1263
1278
  const AUTO_REDEEM_INTERVAL = 60 * 1e3;
1279
+ const TIMEOUT = 15 * 60 * 1e3;
1264
1280
  class Redeemer extends EventEmitter__default.default {
1265
1281
  options;
1266
1282
  running = false;
1267
1283
  timer;
1268
- submitted = /* @__PURE__ */ new Map();
1284
+ records = /* @__PURE__ */ new Map();
1269
1285
  unListenRelayClient;
1270
1286
  constructor(options) {
1271
1287
  super();
@@ -1274,25 +1290,31 @@ class Redeemer extends EventEmitter__default.default {
1274
1290
  }
1275
1291
  listenRelayClient() {
1276
1292
  const { relayClient } = this.options;
1277
- const unListenPost = listenEvent(relayClient, "post", ({ redeem }) => {
1278
- logger.lines(
1279
- `post redeem(待确认):`,
1280
- ...this.toMessages(this.mapSubmittedPositions(redeem))
1281
- );
1282
- });
1283
1293
  const unListenPosted = listenEvent(
1284
1294
  relayClient,
1285
1295
  "posted",
1286
- ({ redeem, error }) => {
1287
- const failedPositions = this.mapSubmittedPositions(redeem.failed);
1288
- if (failedPositions.length > 0) {
1296
+ ({ txHash, redeem, error }) => {
1297
+ const pendingEvents = [...redeem.success];
1298
+ for (const r of redeem.failed) if (!r.done) pendingEvents.push(r);
1299
+ const pendingRecords = this.updateEventRecords(pendingEvents);
1300
+ if (pendingRecords.length > 0) {
1301
+ logger.lines(
1302
+ `🟡 redeem(待确认): ${pendingRecords.length} 个`,
1303
+ ...this.toMessages(pendingRecords)
1304
+ );
1305
+ }
1306
+ const failedRecords = this.updateEventRecords(
1307
+ redeem.failed.filter(({ done }) => done)
1308
+ );
1309
+ if (failedRecords.length > 0) {
1289
1310
  const messages = [
1290
- `🔴 redeem 失败已放弃(重试超限): ${failedPositions.length} 个`,
1291
- ...this.toMessages(failedPositions)
1311
+ `🔴 redeem 失败(重试超限): ${failedRecords.length} 个`,
1312
+ ...this.toMessages(failedRecords)
1292
1313
  ];
1293
- logger.lines(...messages, error);
1314
+ logger.lines(...messages);
1294
1315
  telegramService.info(messages.join("\n"));
1295
1316
  }
1317
+ logger.info("redeem 提交结果:", txHash || error);
1296
1318
  }
1297
1319
  );
1298
1320
  const unListenRequestLimit = listenEvent(
@@ -1311,24 +1333,29 @@ class Redeemer extends EventEmitter__default.default {
1311
1333
  telegramService.info("AutoRedeem 已重启");
1312
1334
  });
1313
1335
  return () => {
1314
- unListenPost();
1315
1336
  unListenPosted();
1316
1337
  unListenRequestLimit();
1317
1338
  unListenResets();
1318
1339
  };
1319
1340
  }
1320
- mapSubmittedPositions(conditions) {
1321
- const positions = [];
1322
- for (const cId of conditions) {
1323
- const position = this.submitted.get(cId);
1324
- if (position) {
1325
- positions.push(position);
1326
- } else {
1327
- logger.error("no submitted failed position", cId);
1328
- telegramService.error(`no submitted failed position: ${cId}`);
1341
+ updateEventRecords(events) {
1342
+ const records = [];
1343
+ for (const { conditionId, execCount } of events) {
1344
+ const record = this.getRecord(conditionId);
1345
+ if (record) {
1346
+ record.execCount = execCount;
1347
+ records.push(record);
1329
1348
  }
1330
1349
  }
1331
- return positions;
1350
+ return records;
1351
+ }
1352
+ getRecord(conditionId) {
1353
+ const record = this.records.get(conditionId);
1354
+ if (!record) {
1355
+ logger.error("no record for", conditionId);
1356
+ telegramService.error(`no record for: ${conditionId}`);
1357
+ }
1358
+ return record;
1332
1359
  }
1333
1360
  /**
1334
1361
  * 获取可 Redeem 的仓位
@@ -1365,9 +1392,9 @@ class Redeemer extends EventEmitter__default.default {
1365
1392
  }
1366
1393
  return positions;
1367
1394
  }
1368
- toMessages(positions) {
1369
- return positions.map(
1370
- (position) => ` - ${position.slug} ${position.outcome}: ${position.currentValue} USDC`
1395
+ toMessages(eventRecords) {
1396
+ return eventRecords.map(
1397
+ ({ position, execCount, postSuccessTime }) => ` - ${position.slug} ${position.outcome}: ${position.currentValue} USDC (执行次数: ${execCount} ${postSuccessTime ? `确认时长: ${(Date.now() - postSuccessTime) / 1e3}s` : ""})`
1371
1398
  );
1372
1399
  }
1373
1400
  async autoRedeem() {
@@ -1378,36 +1405,64 @@ class Redeemer extends EventEmitter__default.default {
1378
1405
  logger.error("自动 redeem: 获取仓位失败", error);
1379
1406
  return;
1380
1407
  }
1408
+ const preSize = this.records.size;
1381
1409
  for (const position of redeemablePositions) {
1382
1410
  const conditionId = position.conditionId;
1383
- if (!this.submitted.has(conditionId)) {
1411
+ let record = this.records.get(conditionId);
1412
+ if (!record) {
1413
+ record = {
1414
+ position,
1415
+ execCount: 0,
1416
+ timeout: false
1417
+ };
1418
+ this.records.set(conditionId, record);
1384
1419
  const relayClient = this.options.relayClient;
1385
- relayClient.submitRedeem(conditionId).catch((error) => {
1420
+ relayClient.submitRedeem(conditionId).then(() => {
1421
+ record.postSuccessTime = Date.now();
1422
+ }).catch((error) => {
1386
1423
  if (relayClient.isSubmitError(error)) {
1387
1424
  logger.error("submitRedeem failed:", conditionId, error);
1388
1425
  telegramService.error(`submitRedeem failed: ${conditionId}`);
1389
1426
  }
1390
1427
  });
1391
1428
  }
1392
- this.submitted.set(conditionId, position);
1429
+ record.position = position;
1393
1430
  }
1394
- const successPositions = [];
1395
- for (const [conditionId, position] of this.submitted.entries()) {
1396
- if (!redeemablePositions.some((p) => p.conditionId === conditionId)) {
1397
- successPositions.push(position);
1398
- this.submitted.delete(conditionId);
1431
+ const now = Date.now();
1432
+ const successRecords = [];
1433
+ const timeoutRecords = [];
1434
+ for (const [conditionId, record] of this.records.entries()) {
1435
+ if (redeemablePositions.some((p) => p.conditionId === conditionId)) {
1436
+ if (!record.timeout && record.postSuccessTime && now - record.postSuccessTime >= TIMEOUT) {
1437
+ record.timeout = true;
1438
+ timeoutRecords.push(record);
1439
+ }
1440
+ } else {
1441
+ successRecords.push(record);
1442
+ this.records.delete(conditionId);
1399
1443
  }
1400
1444
  }
1401
- if (successPositions.length > 0) {
1445
+ if (timeoutRecords.length > 0) {
1402
1446
  const messages = [
1403
- `🟢 redeem 成功: ${successPositions.length} 个`,
1404
- ...this.toMessages(successPositions)
1447
+ `🔴 redeem 超时: ${timeoutRecords.length} 个`,
1448
+ ...this.toMessages(timeoutRecords)
1405
1449
  ];
1406
1450
  logger.lines(...messages);
1407
1451
  telegramService.info(messages.join("\n"));
1408
1452
  }
1409
- logger.info(`redeem 待确认总数: ${this.submitted.size} 个`);
1410
- if (successPositions.length > 0) this.emit("redeemed");
1453
+ if (successRecords.length > 0) {
1454
+ const messages = [
1455
+ `🟢 redeem 成功: ${successRecords.length} 个`,
1456
+ ...this.toMessages(successRecords)
1457
+ ];
1458
+ logger.lines(...messages);
1459
+ telegramService.info(messages.join("\n"));
1460
+ this.emit("redeemed");
1461
+ }
1462
+ const curSize = this.records.size;
1463
+ if (curSize !== preSize) {
1464
+ logger.info(`redeem 待确认总数: ${curSize} 个`);
1465
+ }
1411
1466
  }
1412
1467
  start() {
1413
1468
  if (this.running) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "polycopy",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "polycopy test",
5
5
  "main": "dist/index.js",
6
6
  "bin": {