capitalisk-dex 17.3.0 → 18.0.0

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.
@@ -1,11 +1,11 @@
1
1
  module.exports = {
2
2
  passiveMode: false,
3
3
  priceDecimalPrecision: null,
4
- initRetryDelay: 5000,
4
+ initRetryDelay: 20000,
5
5
  multisigExpiry: 86400000,
6
6
  multisigExpiryCheckInterval: 60000,
7
7
  multisigFlushInterval: 15000,
8
- multisigReadyDelay: 5000,
8
+ multisigReadyDelay: 15000,
9
9
  multisigMaxBatchSize: 25,
10
10
  multisigRetryInterval: 60000,
11
11
  recentTransfersExpiry: 1800000,
package/index.js CHANGED
@@ -21,7 +21,7 @@ const { CAPITALISK_DEX_PASSWORD } = process.env;
21
21
  const CIPHER_ALGORITHM = 'aes-192-cbc';
22
22
  const CIPHER_KEY = CAPITALISK_DEX_PASSWORD ? crypto.scryptSync(CAPITALISK_DEX_PASSWORD, 'salt', 24) : undefined;
23
23
  const CIPHER_IV = Buffer.alloc(16, 0);
24
- const DEFAULT_INIT_RETRY_DELAY = 5000;
24
+ const DEFAULT_INIT_RETRY_DELAY = 20000;
25
25
  const DEFAULT_MULTISIG_READY_DELAY = 5000;
26
26
  const DEFAULT_MULTISIG_RETRY_INTERVAL = 60000;
27
27
  const DEFAULT_SIGNATURE_READY_DELAY = 10000;
@@ -95,6 +95,7 @@ module.exports = class CapitaliskDEXModule {
95
95
  this.isQuoteChainForked = false;
96
96
  this.lastSnapshot = null;
97
97
  this.finalizedSnapshot = null;
98
+ this.scheduledTransferInfos = [];
98
99
  this.pendingTransfers = new Map();
99
100
  this.chainSymbols.forEach((chainSymbol) => {
100
101
  this.multisigWalletInfo[chainSymbol] = {
@@ -1203,7 +1204,7 @@ module.exports = class CapitaliskDEXModule {
1203
1204
  `Failed to load initial snapshot because of error: ${error.message} - DEX node will start with an empty order book`
1204
1205
  );
1205
1206
 
1206
- while (!this.processedHeights[this.baseChainSymbol] || !this.processedHeights[this.quoteChainSymbol]) {
1207
+ while (true) {
1207
1208
  try {
1208
1209
  let [baseMaxHeight, quoteMaxHeight] = await Promise.all([
1209
1210
  this._getMaxBlockHeight(this.baseChainSymbol, false),
@@ -1216,31 +1217,37 @@ module.exports = class CapitaliskDEXModule {
1216
1217
  this.logger.error(`The ${this.quoteChainSymbol} chain had a height of 0`);
1217
1218
  }
1218
1219
  if (!baseMaxHeight || !quoteMaxHeight) {
1219
- this.logger.debug('Retrying chain time initialization...');
1220
- await wait(this.initRetryDelay);
1221
- continue;
1220
+ throw new Error('Invalid chain heights');
1222
1221
  }
1223
1222
  this.processedHeights[this.baseChainSymbol] = baseMaxHeight;
1224
1223
  this.processedHeights[this.quoteChainSymbol] = quoteMaxHeight;
1225
- } catch (orderBookInitError) {
1226
- throw new Error(
1227
- `Failed to initialize new order book because of error: ${orderBookInitError.message}`
1224
+ break;
1225
+ } catch (initHeightError) {
1226
+ this.logger.error(
1227
+ `Failed to initialize last processed heights because of error: ${initHeightError.message}`
1228
1228
  );
1229
+ this.logger.debug('Retrying initialization of last processed heights...');
1230
+ await wait(this.initRetryDelay);
1229
1231
  }
1230
1232
  }
1231
1233
  }
1232
1234
 
1233
- try {
1234
- let [baseChainMaxBlock, quoteChainMaxBlock] = await Promise.all([
1235
- this._getBlockAtHeight(this.baseChainSymbol, this.processedHeights[this.baseChainSymbol]),
1236
- this._getBlockAtHeight(this.quoteChainSymbol, this.processedHeights[this.quoteChainSymbol])
1237
- ]);
1238
- this.lastProcessedBlocks[this.baseChainSymbol] = baseChainMaxBlock;
1239
- this.lastProcessedBlocks[this.quoteChainSymbol] = quoteChainMaxBlock;
1240
- } catch (error) {
1241
- throw new Error(
1242
- `Failed to load last processed blocks because of error: ${error.message}`
1243
- );
1235
+ while (true) {
1236
+ try {
1237
+ let [baseChainMaxBlock, quoteChainMaxBlock] = await Promise.all([
1238
+ this._getBlockAtHeight(this.baseChainSymbol, this.processedHeights[this.baseChainSymbol]),
1239
+ this._getBlockAtHeight(this.quoteChainSymbol, this.processedHeights[this.quoteChainSymbol])
1240
+ ]);
1241
+ this.lastProcessedBlocks[this.baseChainSymbol] = baseChainMaxBlock;
1242
+ this.lastProcessedBlocks[this.quoteChainSymbol] = quoteChainMaxBlock;
1243
+ break;
1244
+ } catch (error) {
1245
+ this.logger.error(
1246
+ `Failed to initialize last processed blocks because of error: ${error.message}`
1247
+ );
1248
+ this.logger.debug('Retrying initialization of last processed blocks...');
1249
+ await wait(this.initRetryDelay);
1250
+ }
1244
1251
  }
1245
1252
 
1246
1253
  await Promise.all(
@@ -1436,23 +1443,17 @@ module.exports = class CapitaliskDEXModule {
1436
1443
  ) {
1437
1444
  let currentOrderBook = this.tradeEngine.getSnapshot();
1438
1445
  this.tradeEngine.clear();
1439
- try {
1440
- await this.refundOrderBook(
1441
- {
1442
- orderBook: currentOrderBook,
1443
- chainHeights: {...latestChainHeights}
1444
- },
1445
- latestBlockTimestamp,
1446
- {
1447
- [this.baseChainSymbol]: this.options.chains[this.baseChainSymbol].dexMovedToAddress,
1448
- [this.quoteChainSymbol]: this.options.chains[this.quoteChainSymbol].dexMovedToAddress
1449
- }
1450
- );
1451
- } catch (error) {
1452
- this.logger.error(
1453
- `Failed to refund the order book according to config because of error: ${error.message}`
1454
- );
1455
- }
1446
+ this.scheduleRefundOrderBook(
1447
+ {
1448
+ orderBook: currentOrderBook,
1449
+ chainHeights: {...latestChainHeights}
1450
+ },
1451
+ latestBlockTimestamp,
1452
+ {
1453
+ [this.baseChainSymbol]: this.options.chains[this.baseChainSymbol].dexMovedToAddress,
1454
+ [this.quoteChainSymbol]: this.options.chains[this.quoteChainSymbol].dexMovedToAddress
1455
+ }
1456
+ );
1456
1457
  }
1457
1458
  }
1458
1459
 
@@ -1726,103 +1727,93 @@ module.exports = class CapitaliskDEXModule {
1726
1727
  let disabledOrders = orders.filter(orderTxn => orderTxn.type === 'disabled');
1727
1728
 
1728
1729
  if (!this.passiveMode) {
1729
- movedOrders.forEach(async (orderTxn) => {
1730
+ movedOrders.forEach((orderTxn) => {
1730
1731
  let protocolMessage = this._computeProtocolMessage(orderTxn.sourceChain, 'r5', [orderTxn.id, orderTxn.movedToAddress], 'DEX has moved');
1731
- try {
1732
- await this.execRefundTransaction(orderTxn, latestBlockTimestamp, protocolMessage, {type: 'r5', originOrderId: orderTxn.id});
1733
- } catch (error) {
1734
- this.logger.error(
1735
- `Chain ${chainSymbol}: Failed to post multisig refund transaction for moved DEX order ID ${
1736
- orderTxn.id
1737
- } to ${
1738
- orderTxn.sourceWalletAddress
1739
- } on chain ${
1740
- orderTxn.sourceChain
1741
- } because of error: ${
1742
- error.message
1743
- }`
1744
- );
1745
- }
1732
+ this.scheduleRefundTransaction(
1733
+ orderTxn,
1734
+ latestBlockTimestamp,
1735
+ protocolMessage,
1736
+ {type: 'r5', originOrderId: orderTxn.id},
1737
+ `Chain ${chainSymbol}: Failed to post multisig refund transaction for moved DEX order ID ${
1738
+ orderTxn.id
1739
+ } to ${
1740
+ orderTxn.sourceWalletAddress
1741
+ } on chain ${
1742
+ orderTxn.sourceChain
1743
+ }`
1744
+ );
1746
1745
  });
1747
1746
 
1748
- disabledOrders.forEach(async (orderTxn) => {
1747
+ disabledOrders.forEach((orderTxn) => {
1749
1748
  let protocolMessage = this._computeProtocolMessage(orderTxn.sourceChain, 'r6', [orderTxn.id], 'DEX has been disabled');
1750
- try {
1751
- await this.execRefundTransaction(orderTxn, latestBlockTimestamp, protocolMessage, {type: 'r6', originOrderId: orderTxn.id});
1752
- } catch (error) {
1753
- this.logger.error(
1754
- `Chain ${chainSymbol}: Failed to post multisig refund transaction for disabled DEX order ID ${
1755
- orderTxn.id
1756
- } to ${
1757
- orderTxn.sourceWalletAddress
1758
- } on chain ${
1759
- orderTxn.sourceChain
1760
- } because of error: ${
1761
- error.message
1762
- }`
1763
- );
1764
- }
1749
+ this.scheduleRefundTransaction(
1750
+ orderTxn,
1751
+ latestBlockTimestamp,
1752
+ protocolMessage,
1753
+ {type: 'r6', originOrderId: orderTxn.id},
1754
+ `Chain ${chainSymbol}: Failed to post multisig refund transaction for disabled DEX order ID ${
1755
+ orderTxn.id
1756
+ } to ${
1757
+ orderTxn.sourceWalletAddress
1758
+ } on chain ${
1759
+ orderTxn.sourceChain
1760
+ }`
1761
+ );
1765
1762
  });
1766
1763
 
1767
- invalidOrders.forEach(async (orderTxn) => {
1764
+ invalidOrders.forEach((orderTxn) => {
1768
1765
  let reasonMessage = 'Invalid order';
1769
1766
  if (orderTxn.reason) {
1770
1767
  reasonMessage += ` - ${orderTxn.reason}`;
1771
1768
  }
1772
1769
  let protocolMessage = this._computeProtocolMessage(orderTxn.sourceChain, 'r1', [orderTxn.id], reasonMessage);
1773
- try {
1774
- await this.execRefundTransaction(orderTxn, latestBlockTimestamp, protocolMessage, {type: 'r1', originOrderId: orderTxn.id});
1775
- } catch (error) {
1776
- this.logger.error(
1777
- `Chain ${chainSymbol}: Failed to post multisig refund transaction for invalid order ID ${
1778
- orderTxn.id
1779
- } to ${
1780
- orderTxn.sourceWalletAddress
1781
- } on chain ${
1782
- orderTxn.sourceChain
1783
- } because of error: ${
1784
- error.message
1785
- }`
1786
- );
1787
- }
1770
+ this.scheduleRefundTransaction(
1771
+ orderTxn,
1772
+ latestBlockTimestamp,
1773
+ protocolMessage,
1774
+ {type: 'r1', originOrderId: orderTxn.id},
1775
+ `Chain ${chainSymbol}: Failed to post multisig refund transaction for invalid order ID ${
1776
+ orderTxn.id
1777
+ } to ${
1778
+ orderTxn.sourceWalletAddress
1779
+ } on chain ${
1780
+ orderTxn.sourceChain
1781
+ }`
1782
+ );
1788
1783
  });
1789
1784
 
1790
- oversizedOrders.forEach(async (orderTxn) => {
1785
+ oversizedOrders.forEach((orderTxn) => {
1791
1786
  let protocolMessage = this._computeProtocolMessage(orderTxn.sourceChain, 'r1', [orderTxn.id], 'Oversized order');
1792
- try {
1793
- await this.execRefundTransaction(orderTxn, latestBlockTimestamp, protocolMessage, {type: 'r1', originOrderId: orderTxn.id});
1794
- } catch (error) {
1795
- this.logger.error(
1796
- `Chain ${chainSymbol}: Failed to post multisig refund transaction for oversized order ID ${
1797
- orderTxn.id
1798
- } to ${
1799
- orderTxn.sourceWalletAddress
1800
- } on chain ${
1801
- orderTxn.sourceChain
1802
- } because of error: ${
1803
- error.message
1804
- }`
1805
- );
1806
- }
1787
+ this.scheduleRefundTransaction(
1788
+ orderTxn,
1789
+ latestBlockTimestamp,
1790
+ protocolMessage,
1791
+ {type: 'r1', originOrderId: orderTxn.id},
1792
+ `Chain ${chainSymbol}: Failed to post multisig refund transaction for oversized order ID ${
1793
+ orderTxn.id
1794
+ } to ${
1795
+ orderTxn.sourceWalletAddress
1796
+ } on chain ${
1797
+ orderTxn.sourceChain
1798
+ }`
1799
+ );
1807
1800
  });
1808
1801
 
1809
- undersizedOrders.forEach(async (orderTxn) => {
1802
+ undersizedOrders.forEach((orderTxn) => {
1810
1803
  let protocolMessage = this._computeProtocolMessage(orderTxn.sourceChain, 'r1', [orderTxn.id], 'Undersized order');
1811
- try {
1812
- await this.execRefundTransaction(orderTxn, latestBlockTimestamp, protocolMessage, {type: 'r1', originOrderId: orderTxn.id});
1813
- } catch (error) {
1814
- this.logger.error(
1815
- `Chain ${chainSymbol}: Failed to post multisig refund transaction for undersized order ID ${
1816
- orderTxn.id
1817
- } to ${
1818
- orderTxn.sourceWalletAddress
1819
- } on chain ${
1820
- orderTxn.sourceChain
1821
- } because of error: ${
1822
- error.message
1823
- }`
1824
- );
1825
- }
1804
+ this.scheduleRefundTransaction(
1805
+ orderTxn,
1806
+ latestBlockTimestamp,
1807
+ protocolMessage,
1808
+ {type: 'r1', originOrderId: orderTxn.id},
1809
+ `Chain ${chainSymbol}: Failed to post multisig refund transaction for undersized order ID ${
1810
+ orderTxn.id
1811
+ } to ${
1812
+ orderTxn.sourceWalletAddress
1813
+ } on chain ${
1814
+ orderTxn.sourceChain
1815
+ }`
1816
+ );
1826
1817
  });
1827
1818
  }
1828
1819
 
@@ -1832,7 +1823,7 @@ module.exports = class CapitaliskDEXModule {
1832
1823
  } else {
1833
1824
  expiredOrders = this.tradeEngine.expireAskOrders(chainHeight);
1834
1825
  }
1835
- expiredOrders.forEach(async (expiredOrder) => {
1826
+ expiredOrders.forEach((expiredOrder) => {
1836
1827
  this.logger.info(
1837
1828
  `Chain ${chainSymbol}: Order ${expiredOrder.id} at height ${expiredOrder.height} expired`
1838
1829
  );
@@ -1840,30 +1831,23 @@ module.exports = class CapitaliskDEXModule {
1840
1831
  return;
1841
1832
  }
1842
1833
  let protocolMessage = this._computeProtocolMessage(expiredOrder.sourceChain, 'r2', [expiredOrder.id], 'Expired order');
1843
- try {
1844
- await this.refundOrder(
1845
- expiredOrder,
1846
- latestBlockTimestamp,
1847
- expiredOrder.expiryHeight,
1848
- protocolMessage,
1849
- {type: 'r2', originOrderId: expiredOrder.id}
1850
- );
1851
- } catch (error) {
1852
- this.logger.error(
1853
- `Chain ${chainSymbol}: Failed to post multisig refund transaction for expired order ID ${
1854
- expiredOrder.id
1855
- } to ${
1856
- expiredOrder.sourceWalletAddress
1857
- } on chain ${
1858
- expiredOrder.sourceChain
1859
- } because of error: ${
1860
- error.message
1861
- }`
1862
- );
1863
- }
1834
+ this.scheduleRefundOrder(
1835
+ expiredOrder,
1836
+ latestBlockTimestamp,
1837
+ expiredOrder.expiryHeight,
1838
+ protocolMessage,
1839
+ {type: 'r2', originOrderId: expiredOrder.id},
1840
+ `Chain ${chainSymbol}: Failed to post multisig refund transaction for expired order ID ${
1841
+ expiredOrder.id
1842
+ } to ${
1843
+ expiredOrder.sourceWalletAddress
1844
+ } on chain ${
1845
+ expiredOrder.sourceChain
1846
+ }`
1847
+ );
1864
1848
  });
1865
1849
 
1866
- closeOrders.forEach(async (orderTxn) => {
1850
+ closeOrders.forEach((orderTxn) => {
1867
1851
  let targetOrder = this.tradeEngine.getOrder(orderTxn.orderIdToClose);
1868
1852
  if (!targetOrder) {
1869
1853
  this.logger.warn(
@@ -1895,29 +1879,22 @@ module.exports = class CapitaliskDEXModule {
1895
1879
  return;
1896
1880
  }
1897
1881
  let protocolMessage = this._computeProtocolMessage(refundTxn.sourceChain, 'r3', [targetOrder.id, orderTxn.id], 'Closed order');
1898
- try {
1899
- await this.execRefundTransaction(
1900
- refundTxn,
1901
- latestBlockTimestamp,
1902
- protocolMessage,
1903
- {type: 'r3', originOrderId: targetOrder.id, closerOrderId: orderTxn.id}
1904
- );
1905
- } catch (error) {
1906
- this.logger.error(
1907
- `Chain ${chainSymbol}: Failed to post multisig refund transaction for closed order ID ${
1908
- targetOrder.id
1909
- } to ${
1910
- targetOrder.sourceWalletAddress
1911
- } on chain ${
1912
- targetOrder.sourceChain
1913
- } because of error: ${
1914
- error.message
1915
- }`
1916
- );
1917
- }
1882
+ this.scheduleRefundTransaction(
1883
+ refundTxn,
1884
+ latestBlockTimestamp,
1885
+ protocolMessage,
1886
+ {type: 'r3', originOrderId: targetOrder.id, closerOrderId: orderTxn.id},
1887
+ `Chain ${chainSymbol}: Failed to post multisig refund transaction for closed order ID ${
1888
+ targetOrder.id
1889
+ } to ${
1890
+ targetOrder.sourceWalletAddress
1891
+ } on chain ${
1892
+ targetOrder.sourceChain
1893
+ }`
1894
+ );
1918
1895
  });
1919
1896
 
1920
- limitAndMarketOrders.forEach(async (orderTxn) => {
1897
+ limitAndMarketOrders.forEach((orderTxn) => {
1921
1898
  let result;
1922
1899
  try {
1923
1900
  result = this.tradeEngine.addOrder(orderTxn);
@@ -1944,7 +1921,7 @@ module.exports = class CapitaliskDEXModule {
1944
1921
 
1945
1922
  let makerCount = 0;
1946
1923
 
1947
- result.makers.forEach(async (makerOrder) => {
1924
+ result.makers.forEach((makerOrder) => {
1948
1925
  let makerChainOptions = this.options.chains[makerOrder.targetChain];
1949
1926
  let makerAddress = makerOrder.targetWalletAddress;
1950
1927
  let makerAmount = makerOrder.targetChain === this.baseChainSymbol ? makerOrder.lastValueTaken : makerOrder.lastSizeTaken;
@@ -1973,84 +1950,76 @@ module.exports = class CapitaliskDEXModule {
1973
1950
  [makerOrder.sourceChain, makerOrder.id, result.taker.id],
1974
1951
  'Order made'
1975
1952
  );
1976
- try {
1977
- await this.execMultisigTransaction(
1978
- makerOrder.targetChain,
1979
- makerTxn,
1980
- protocolMessage,
1981
- {type: 't2', originOrderId: makerOrder.id, makerOrderId: makerOrder.id, takerOrderId: result.taker.id}
1982
- );
1983
- } catch (error) {
1984
- this.logger.error(
1985
- `Chain ${chainSymbol}: Failed to post multisig transaction of maker ${makerAddress} on chain ${makerOrder.targetChain} because of error: ${error.message}`
1986
- );
1987
- }
1953
+ this.scheduleMultisigTransaction(
1954
+ makerOrder.targetChain,
1955
+ makerTxn,
1956
+ protocolMessage,
1957
+ {type: 't2', originOrderId: makerOrder.id, makerOrderId: makerOrder.id, takerOrderId: result.taker.id},
1958
+ `Chain ${chainSymbol}: Failed to post multisig transaction of maker ${makerAddress} on chain ${makerOrder.targetChain}`
1959
+ );
1988
1960
  });
1989
1961
 
1990
- (async () => {
1991
- if (!makerCount) {
1992
- return;
1993
- }
1994
- if (takerAmount <= 0n) {
1995
- this.logger.warn(
1996
- `Chain ${chainSymbol}: Did not post the taker trade order ${orderTxn.id} because the amount after fees was less than or equal to 0`
1962
+ if (makerCount) {
1963
+ if (takerAmount > 0n) {
1964
+ let takerTxn = {
1965
+ recipientAddress: takerAddress,
1966
+ amount: takerAmount.toString(),
1967
+ fee: takerChainOptions.exchangeFeeBase.toString(),
1968
+ timestamp: latestBlockTimestamp,
1969
+ height: latestChainHeights[takerTargetChain]
1970
+ };
1971
+ let protocolMessage = this._computeProtocolMessage(
1972
+ takerTargetChain,
1973
+ 't1',
1974
+ [result.taker.sourceChain, result.taker.id, makerCount],
1975
+ 'Orders taken'
1997
1976
  );
1998
- return;
1999
- }
2000
- let takerTxn = {
2001
- recipientAddress: takerAddress,
2002
- amount: takerAmount.toString(),
2003
- fee: takerChainOptions.exchangeFeeBase.toString(),
2004
- timestamp: latestBlockTimestamp,
2005
- height: latestChainHeights[takerTargetChain]
2006
- };
2007
- let protocolMessage = this._computeProtocolMessage(
2008
- takerTargetChain,
2009
- 't1',
2010
- [result.taker.sourceChain, result.taker.id, makerCount],
2011
- 'Orders taken'
2012
- );
2013
- try {
2014
- await this.execMultisigTransaction(
1977
+ this.scheduleMultisigTransaction(
2015
1978
  takerTargetChain,
2016
1979
  takerTxn,
2017
1980
  protocolMessage,
2018
- {type: 't1', originOrderId: result.taker.id, takerOrderId: result.taker.id, makerCount}
1981
+ {type: 't1', originOrderId: result.taker.id, takerOrderId: result.taker.id, makerCount},
1982
+ `Chain ${chainSymbol}: Failed to post multisig transaction of taker ${takerAddress} on chain ${takerTargetChain}`
2019
1983
  );
2020
- } catch (error) {
2021
- this.logger.error(
2022
- `Chain ${chainSymbol}: Failed to post multisig transaction of taker ${takerAddress} on chain ${takerTargetChain} because of error: ${error.message}`
1984
+ } else {
1985
+ this.logger.warn(
1986
+ `Chain ${chainSymbol}: Did not post the taker trade order ${orderTxn.id} because the amount after fees was less than or equal to 0`
2023
1987
  );
2024
1988
  }
2025
- })();
2026
-
2027
- (async () => {
2028
- if (orderTxn.type === 'market') {
2029
- let refundTxn = {
2030
- sourceChain: result.taker.sourceChain,
2031
- sourceWalletAddress: result.taker.sourceWalletAddress,
2032
- height: orderTxn.height
2033
- };
2034
- if (result.taker.sourceChain === this.baseChainSymbol) {
2035
- refundTxn.sourceChainAmount = result.taker.valueRemaining;
2036
- } else {
2037
- refundTxn.sourceChainAmount = result.taker.sizeRemaining;
2038
- }
2039
- if (refundTxn.sourceChainAmount <= 0n) {
2040
- return;
2041
- }
1989
+ }
1990
+
1991
+ if (orderTxn.type === 'market') {
1992
+ let refundTxn = {
1993
+ sourceChain: result.taker.sourceChain,
1994
+ sourceWalletAddress: result.taker.sourceWalletAddress,
1995
+ height: orderTxn.height
1996
+ };
1997
+ if (result.taker.sourceChain === this.baseChainSymbol) {
1998
+ refundTxn.sourceChainAmount = result.taker.valueRemaining;
1999
+ } else {
2000
+ refundTxn.sourceChainAmount = result.taker.sizeRemaining;
2001
+ }
2002
+ if (refundTxn.sourceChainAmount > 0n) {
2042
2003
  let protocolMessage = this._computeProtocolMessage(refundTxn.sourceChain, 'r4', [orderTxn.id], 'Unmatched market order part');
2043
- try {
2044
- await this.execRefundTransaction(refundTxn, latestBlockTimestamp, protocolMessage, {type: 'r4', originOrderId: orderTxn.id});
2045
- } catch (error) {
2046
- this.logger.error(
2047
- `Chain ${chainSymbol}: Failed to post multisig market order refund transaction of taker ${takerAddress} on chain ${takerTargetChain} because of error: ${error.message}`
2048
- );
2049
- }
2004
+ this.scheduleRefundTransaction(
2005
+ refundTxn,
2006
+ latestBlockTimestamp,
2007
+ protocolMessage,
2008
+ {type: 'r4', originOrderId: orderTxn.id},
2009
+ `Chain ${
2010
+ chainSymbol
2011
+ }: Failed to post multisig market order refund transaction of taker ${
2012
+ takerAddress
2013
+ } on chain ${
2014
+ takerTargetChain
2015
+ }`
2016
+ );
2050
2017
  }
2051
- })();
2018
+ }
2052
2019
  });
2053
2020
 
2021
+ await this.flushScheduledTransactions();
2022
+
2054
2023
  this.processedHeights = {...latestChainHeights};
2055
2024
  this.lastProcessedBlocks[blockData.chainSymbol] = blockData;
2056
2025
  }
@@ -2114,34 +2083,33 @@ module.exports = class CapitaliskDEXModule {
2114
2083
  fromHeight,
2115
2084
  toHeight
2116
2085
  });
2117
- await Promise.all(
2118
- dividendList.map(async (dividend) => {
2119
- let txnAmount = dividend.amount - BigInt(chainOptions.exchangeFeeBase);
2120
- if (txnAmount <= 0n) {
2121
- this.logger.debug(
2122
- `Chain ${chainSymbol}: Skipped dividend distribution to member address ${
2123
- dividend.walletAddress
2124
- } because the amount due after fees was less than or equal to 0`
2125
- );
2126
- return;
2127
- }
2128
- let dividendTxn = {
2129
- recipientAddress: dividend.walletAddress,
2130
- amount: txnAmount.toString(),
2131
- fee: chainOptions.exchangeFeeBase.toString(),
2132
- timestamp: latestBlockTimestamp,
2133
- height: chainHeight
2134
- };
2135
- let protocolMessage = this._computeProtocolMessage(chainSymbol, 'd1', [fromHeight + 1, toHeight], 'Member dividend');
2136
- try {
2137
- await this.execMultisigTransaction(chainSymbol, dividendTxn, protocolMessage);
2138
- } catch (error) {
2139
- this.logger.error(
2140
- `Chain ${chainSymbol}: Failed to post multisig dividend transaction to member address ${dividend.walletAddress} because of error: ${error.message}`
2141
- );
2142
- }
2143
- })
2144
- );
2086
+
2087
+ for (let dividend of dividendList) {
2088
+ let txnAmount = dividend.amount - BigInt(chainOptions.exchangeFeeBase);
2089
+ if (txnAmount <= 0n) {
2090
+ this.logger.debug(
2091
+ `Chain ${chainSymbol}: Skipped dividend distribution to member address ${
2092
+ dividend.walletAddress
2093
+ } because the amount due after fees was less than or equal to 0`
2094
+ );
2095
+ continue;
2096
+ }
2097
+ let dividendTxn = {
2098
+ recipientAddress: dividend.walletAddress,
2099
+ amount: txnAmount.toString(),
2100
+ fee: chainOptions.exchangeFeeBase.toString(),
2101
+ timestamp: latestBlockTimestamp,
2102
+ height: chainHeight
2103
+ };
2104
+ let protocolMessage = this._computeProtocolMessage(chainSymbol, 'd1', [fromHeight + 1, toHeight], 'Member dividend');
2105
+ this.scheduleMultisigTransaction(
2106
+ chainSymbol,
2107
+ dividendTxn,
2108
+ protocolMessage,
2109
+ null,
2110
+ `Chain ${chainSymbol}: Failed to post multisig dividend transaction to member address ${dividend.walletAddress}`
2111
+ );
2112
+ }
2145
2113
  };
2146
2114
 
2147
2115
  let baseChainForkTargetHeight = 0;
@@ -2632,37 +2600,36 @@ module.exports = class CapitaliskDEXModule {
2632
2600
  return block;
2633
2601
  }
2634
2602
 
2635
- async refundOrderBook(snapshot, timestamp, movedToAddresses) {
2603
+ scheduleRefundOrderBook(snapshot, timestamp, movedToAddresses) {
2636
2604
  let allOrders = snapshot.orderBook.bidLimitOrders.concat(snapshot.orderBook.askLimitOrders);
2637
- await Promise.all(
2638
- allOrders.map(async (order) => {
2639
- let movedToAddress = movedToAddresses[order.sourceChain];
2640
- if (movedToAddress) {
2641
- let protocolMessage = this._computeProtocolMessage(order.sourceChain, 'r5', [order.id, movedToAddress], 'DEX has moved');
2642
- await this.refundOrder(
2643
- order,
2644
- timestamp,
2645
- snapshot.chainHeights[order.sourceChain],
2646
- protocolMessage,
2647
- {type: 'r5', originOrderId: order.id}
2648
- );
2649
- } else {
2650
- let protocolMessage = this._computeProtocolMessage(order.sourceChain, 'r6', [order.id], 'DEX has been disabled');
2651
- allOrders.map(async (order) => {
2652
- await this.refundOrder(
2653
- order,
2654
- timestamp,
2655
- snapshot.chainHeights[order.sourceChain],
2656
- protocolMessage,
2657
- {type: 'r6', originOrderId: order.id}
2658
- );
2659
- })
2660
- }
2661
- })
2662
- );
2605
+ for (let order of allOrders) {
2606
+ let movedToAddress = movedToAddresses[order.sourceChain];
2607
+ let failureMessage = `Failed to post refund transaction for order ${order.id} as part of full order book refund`;
2608
+ if (movedToAddress) {
2609
+ let protocolMessage = this._computeProtocolMessage(order.sourceChain, 'r5', [order.id, movedToAddress], 'DEX has moved');
2610
+ this.scheduleRefundOrder(
2611
+ order,
2612
+ timestamp,
2613
+ snapshot.chainHeights[order.sourceChain],
2614
+ protocolMessage,
2615
+ {type: 'r5', originOrderId: order.id},
2616
+ failureMessage
2617
+ );
2618
+ } else {
2619
+ let protocolMessage = this._computeProtocolMessage(order.sourceChain, 'r6', [order.id], 'DEX has been disabled');
2620
+ this.scheduleRefundOrder(
2621
+ order,
2622
+ timestamp,
2623
+ snapshot.chainHeights[order.sourceChain],
2624
+ protocolMessage,
2625
+ {type: 'r6', originOrderId: order.id},
2626
+ failureMessage
2627
+ );
2628
+ }
2629
+ }
2663
2630
  }
2664
2631
 
2665
- async refundOrder(order, timestamp, refundHeight, reason, extraTransferData) {
2632
+ scheduleRefundOrder(order, timestamp, refundHeight, reason, extraTransferData, failureMessage) {
2666
2633
  let refundTxn = {
2667
2634
  sourceChain: order.sourceChain,
2668
2635
  sourceWalletAddress: order.sourceWalletAddress,
@@ -2673,7 +2640,7 @@ module.exports = class CapitaliskDEXModule {
2673
2640
  } else {
2674
2641
  refundTxn.sourceChainAmount = order.sizeRemaining;
2675
2642
  }
2676
- await this.execRefundTransaction(refundTxn, timestamp, reason, extraTransferData);
2643
+ this.scheduleRefundTransaction(refundTxn, timestamp, reason, extraTransferData, failureMessage);
2677
2644
  }
2678
2645
 
2679
2646
  _computeProtocolMessage(chainSymbol, code, args, reasonMessage) {
@@ -2690,15 +2657,16 @@ module.exports = class CapitaliskDEXModule {
2690
2657
  return messageParts.join(': ');
2691
2658
  }
2692
2659
 
2693
- async execRefundTransaction(txn, timestamp, reason, extraTransferData) {
2660
+ scheduleRefundTransaction(txn, timestamp, reason, extraTransferData, failureMessage) {
2694
2661
  let refundChainOptions = this.options.chains[txn.sourceChain];
2662
+ // Refunds do not charge the exchangeFeeRate.
2695
2663
  let refundAmount = txn.sourceChainAmount - BigInt(refundChainOptions.exchangeFeeBase);
2696
2664
 
2697
- // Refunds do not charge the exchangeFeeRate.
2698
2665
  if (refundAmount <= 0n) {
2699
- throw new Error(
2700
- 'Failed to make refund because amount was less than or equal to 0'
2666
+ this.logger.debug(
2667
+ `${failureMessage} because amount was less than or equal to 0`
2701
2668
  );
2669
+ return;
2702
2670
  }
2703
2671
 
2704
2672
  let refundTxn = {
@@ -2708,11 +2676,13 @@ module.exports = class CapitaliskDEXModule {
2708
2676
  timestamp,
2709
2677
  height: txn.height
2710
2678
  };
2711
- await this.execMultisigTransaction(
2679
+
2680
+ this.scheduleMultisigTransaction(
2712
2681
  txn.sourceChain,
2713
2682
  refundTxn,
2714
2683
  reason,
2715
- extraTransferData
2684
+ extraTransferData,
2685
+ failureMessage
2716
2686
  );
2717
2687
  }
2718
2688
 
@@ -2731,6 +2701,37 @@ module.exports = class CapitaliskDEXModule {
2731
2701
  }
2732
2702
  }
2733
2703
 
2704
+ scheduleMultisigTransaction(targetChain, transactionData, message, extraTransferData, failureMessage) {
2705
+ this.scheduledTransferInfos.push({
2706
+ targetChain,
2707
+ transactionData,
2708
+ message,
2709
+ extraTransferData,
2710
+ failureMessage
2711
+ });
2712
+ }
2713
+
2714
+ async flushScheduledTransactions() {
2715
+ for (let scheduledTransferInfo of this.scheduledTransferInfos) {
2716
+ let {
2717
+ targetChain,
2718
+ transactionData,
2719
+ message,
2720
+ extraTransferData,
2721
+ failureMessage
2722
+ } = scheduledTransferInfo;
2723
+
2724
+ try {
2725
+ await this.execMultisigTransaction(targetChain, transactionData, message, extraTransferData);
2726
+ } catch (error) {
2727
+ this.logger.debug(
2728
+ `${failureMessage} because of error: ${error.message}`
2729
+ );
2730
+ }
2731
+ }
2732
+ this.scheduledTransferInfos = [];
2733
+ }
2734
+
2734
2735
  async execMultisigTransaction(targetChain, transactionData, message, extraTransferData) {
2735
2736
  let chainTimestamp = this._denormalizeTimestamp(targetChain, transactionData.timestamp);
2736
2737
  let chainCrypto = this.chainCrypto[targetChain];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capitalisk-dex",
3
- "version": "17.3.0",
3
+ "version": "18.0.0",
4
4
  "description": "Decentralized exchange module.",
5
5
  "main": "index.js",
6
6
  "scripts": {