capitalisk-dex 17.3.1 → 18.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.
@@ -5,7 +5,7 @@ module.exports = {
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
@@ -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] = {
@@ -1329,6 +1330,8 @@ module.exports = class CapitaliskDEXModule {
1329
1330
  `Chain ${chainSymbol}: Processing block at height ${chainHeight}`
1330
1331
  );
1331
1332
 
1333
+ this.scheduledTransferInfos = [];
1334
+
1332
1335
  let baseChainHeight = latestChainHeights[this.baseChainSymbol];
1333
1336
  if (baseChainHeight < this.options.dexEnabledFromHeight) {
1334
1337
  this.logger.info(
@@ -1442,23 +1445,17 @@ module.exports = class CapitaliskDEXModule {
1442
1445
  ) {
1443
1446
  let currentOrderBook = this.tradeEngine.getSnapshot();
1444
1447
  this.tradeEngine.clear();
1445
- try {
1446
- await this.refundOrderBook(
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
- );
1457
- } catch (error) {
1458
- this.logger.error(
1459
- `Failed to refund the order book according to config because of error: ${error.message}`
1460
- );
1461
- }
1448
+ this.scheduleRefundOrderBook(
1449
+ {
1450
+ orderBook: currentOrderBook,
1451
+ chainHeights: {...latestChainHeights}
1452
+ },
1453
+ latestBlockTimestamp,
1454
+ {
1455
+ [this.baseChainSymbol]: this.options.chains[this.baseChainSymbol].dexMovedToAddress,
1456
+ [this.quoteChainSymbol]: this.options.chains[this.quoteChainSymbol].dexMovedToAddress
1457
+ }
1458
+ );
1462
1459
  }
1463
1460
  }
1464
1461
 
@@ -1732,103 +1729,93 @@ module.exports = class CapitaliskDEXModule {
1732
1729
  let disabledOrders = orders.filter(orderTxn => orderTxn.type === 'disabled');
1733
1730
 
1734
1731
  if (!this.passiveMode) {
1735
- movedOrders.forEach(async (orderTxn) => {
1732
+ movedOrders.forEach((orderTxn) => {
1736
1733
  let protocolMessage = this._computeProtocolMessage(orderTxn.sourceChain, 'r5', [orderTxn.id, orderTxn.movedToAddress], 'DEX has moved');
1737
- try {
1738
- await this.execRefundTransaction(orderTxn, latestBlockTimestamp, protocolMessage, {type: 'r5', originOrderId: orderTxn.id});
1739
- } catch (error) {
1740
- this.logger.error(
1741
- `Chain ${chainSymbol}: Failed to post multisig refund transaction for moved DEX order ID ${
1742
- orderTxn.id
1743
- } to ${
1744
- orderTxn.sourceWalletAddress
1745
- } on chain ${
1746
- orderTxn.sourceChain
1747
- } because of error: ${
1748
- error.message
1749
- }`
1750
- );
1751
- }
1734
+ this.scheduleRefundTransaction(
1735
+ orderTxn,
1736
+ latestBlockTimestamp,
1737
+ protocolMessage,
1738
+ {type: 'r5', originOrderId: orderTxn.id},
1739
+ `Chain ${chainSymbol}: Failed to post multisig refund transaction for moved DEX order ID ${
1740
+ orderTxn.id
1741
+ } to ${
1742
+ orderTxn.sourceWalletAddress
1743
+ } on chain ${
1744
+ orderTxn.sourceChain
1745
+ }`
1746
+ );
1752
1747
  });
1753
1748
 
1754
- disabledOrders.forEach(async (orderTxn) => {
1749
+ disabledOrders.forEach((orderTxn) => {
1755
1750
  let protocolMessage = this._computeProtocolMessage(orderTxn.sourceChain, 'r6', [orderTxn.id], 'DEX has been disabled');
1756
- try {
1757
- await this.execRefundTransaction(orderTxn, latestBlockTimestamp, protocolMessage, {type: 'r6', originOrderId: orderTxn.id});
1758
- } catch (error) {
1759
- this.logger.error(
1760
- `Chain ${chainSymbol}: Failed to post multisig refund transaction for disabled DEX order ID ${
1761
- orderTxn.id
1762
- } to ${
1763
- orderTxn.sourceWalletAddress
1764
- } on chain ${
1765
- orderTxn.sourceChain
1766
- } because of error: ${
1767
- error.message
1768
- }`
1769
- );
1770
- }
1751
+ this.scheduleRefundTransaction(
1752
+ orderTxn,
1753
+ latestBlockTimestamp,
1754
+ protocolMessage,
1755
+ {type: 'r6', originOrderId: orderTxn.id},
1756
+ `Chain ${chainSymbol}: Failed to post multisig refund transaction for disabled DEX order ID ${
1757
+ orderTxn.id
1758
+ } to ${
1759
+ orderTxn.sourceWalletAddress
1760
+ } on chain ${
1761
+ orderTxn.sourceChain
1762
+ }`
1763
+ );
1771
1764
  });
1772
1765
 
1773
- invalidOrders.forEach(async (orderTxn) => {
1766
+ invalidOrders.forEach((orderTxn) => {
1774
1767
  let reasonMessage = 'Invalid order';
1775
1768
  if (orderTxn.reason) {
1776
1769
  reasonMessage += ` - ${orderTxn.reason}`;
1777
1770
  }
1778
1771
  let protocolMessage = this._computeProtocolMessage(orderTxn.sourceChain, 'r1', [orderTxn.id], reasonMessage);
1779
- try {
1780
- await this.execRefundTransaction(orderTxn, latestBlockTimestamp, protocolMessage, {type: 'r1', originOrderId: orderTxn.id});
1781
- } catch (error) {
1782
- this.logger.error(
1783
- `Chain ${chainSymbol}: Failed to post multisig refund transaction for invalid order ID ${
1784
- orderTxn.id
1785
- } to ${
1786
- orderTxn.sourceWalletAddress
1787
- } on chain ${
1788
- orderTxn.sourceChain
1789
- } because of error: ${
1790
- error.message
1791
- }`
1792
- );
1793
- }
1772
+ this.scheduleRefundTransaction(
1773
+ orderTxn,
1774
+ latestBlockTimestamp,
1775
+ protocolMessage,
1776
+ {type: 'r1', originOrderId: orderTxn.id},
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
+ }`
1784
+ );
1794
1785
  });
1795
1786
 
1796
- oversizedOrders.forEach(async (orderTxn) => {
1787
+ oversizedOrders.forEach((orderTxn) => {
1797
1788
  let protocolMessage = this._computeProtocolMessage(orderTxn.sourceChain, 'r1', [orderTxn.id], 'Oversized order');
1798
- try {
1799
- await this.execRefundTransaction(orderTxn, latestBlockTimestamp, protocolMessage, {type: 'r1', originOrderId: orderTxn.id});
1800
- } catch (error) {
1801
- this.logger.error(
1802
- `Chain ${chainSymbol}: Failed to post multisig refund transaction for oversized order ID ${
1803
- orderTxn.id
1804
- } to ${
1805
- orderTxn.sourceWalletAddress
1806
- } on chain ${
1807
- orderTxn.sourceChain
1808
- } because of error: ${
1809
- error.message
1810
- }`
1811
- );
1812
- }
1789
+ this.scheduleRefundTransaction(
1790
+ orderTxn,
1791
+ latestBlockTimestamp,
1792
+ protocolMessage,
1793
+ {type: 'r1', originOrderId: orderTxn.id},
1794
+ `Chain ${chainSymbol}: Failed to post multisig refund transaction for oversized order ID ${
1795
+ orderTxn.id
1796
+ } to ${
1797
+ orderTxn.sourceWalletAddress
1798
+ } on chain ${
1799
+ orderTxn.sourceChain
1800
+ }`
1801
+ );
1813
1802
  });
1814
1803
 
1815
- undersizedOrders.forEach(async (orderTxn) => {
1804
+ undersizedOrders.forEach((orderTxn) => {
1816
1805
  let protocolMessage = this._computeProtocolMessage(orderTxn.sourceChain, 'r1', [orderTxn.id], 'Undersized order');
1817
- try {
1818
- await this.execRefundTransaction(orderTxn, latestBlockTimestamp, protocolMessage, {type: 'r1', originOrderId: orderTxn.id});
1819
- } catch (error) {
1820
- this.logger.error(
1821
- `Chain ${chainSymbol}: Failed to post multisig refund transaction for undersized order ID ${
1822
- orderTxn.id
1823
- } to ${
1824
- orderTxn.sourceWalletAddress
1825
- } on chain ${
1826
- orderTxn.sourceChain
1827
- } because of error: ${
1828
- error.message
1829
- }`
1830
- );
1831
- }
1806
+ this.scheduleRefundTransaction(
1807
+ orderTxn,
1808
+ latestBlockTimestamp,
1809
+ protocolMessage,
1810
+ {type: 'r1', originOrderId: orderTxn.id},
1811
+ `Chain ${chainSymbol}: Failed to post multisig refund transaction for undersized order ID ${
1812
+ orderTxn.id
1813
+ } to ${
1814
+ orderTxn.sourceWalletAddress
1815
+ } on chain ${
1816
+ orderTxn.sourceChain
1817
+ }`
1818
+ );
1832
1819
  });
1833
1820
  }
1834
1821
 
@@ -1838,7 +1825,7 @@ module.exports = class CapitaliskDEXModule {
1838
1825
  } else {
1839
1826
  expiredOrders = this.tradeEngine.expireAskOrders(chainHeight);
1840
1827
  }
1841
- expiredOrders.forEach(async (expiredOrder) => {
1828
+ expiredOrders.forEach((expiredOrder) => {
1842
1829
  this.logger.info(
1843
1830
  `Chain ${chainSymbol}: Order ${expiredOrder.id} at height ${expiredOrder.height} expired`
1844
1831
  );
@@ -1846,30 +1833,23 @@ module.exports = class CapitaliskDEXModule {
1846
1833
  return;
1847
1834
  }
1848
1835
  let protocolMessage = this._computeProtocolMessage(expiredOrder.sourceChain, 'r2', [expiredOrder.id], 'Expired order');
1849
- try {
1850
- await this.refundOrder(
1851
- expiredOrder,
1852
- latestBlockTimestamp,
1853
- expiredOrder.expiryHeight,
1854
- protocolMessage,
1855
- {type: 'r2', originOrderId: expiredOrder.id}
1856
- );
1857
- } catch (error) {
1858
- this.logger.error(
1859
- `Chain ${chainSymbol}: Failed to post multisig refund transaction for expired order ID ${
1860
- expiredOrder.id
1861
- } to ${
1862
- expiredOrder.sourceWalletAddress
1863
- } on chain ${
1864
- expiredOrder.sourceChain
1865
- } because of error: ${
1866
- error.message
1867
- }`
1868
- );
1869
- }
1836
+ this.scheduleRefundOrder(
1837
+ expiredOrder,
1838
+ latestBlockTimestamp,
1839
+ expiredOrder.expiryHeight,
1840
+ protocolMessage,
1841
+ {type: 'r2', originOrderId: expiredOrder.id},
1842
+ `Chain ${chainSymbol}: Failed to post multisig refund transaction for expired order ID ${
1843
+ expiredOrder.id
1844
+ } to ${
1845
+ expiredOrder.sourceWalletAddress
1846
+ } on chain ${
1847
+ expiredOrder.sourceChain
1848
+ }`
1849
+ );
1870
1850
  });
1871
1851
 
1872
- closeOrders.forEach(async (orderTxn) => {
1852
+ closeOrders.forEach((orderTxn) => {
1873
1853
  let targetOrder = this.tradeEngine.getOrder(orderTxn.orderIdToClose);
1874
1854
  if (!targetOrder) {
1875
1855
  this.logger.warn(
@@ -1901,29 +1881,22 @@ module.exports = class CapitaliskDEXModule {
1901
1881
  return;
1902
1882
  }
1903
1883
  let protocolMessage = this._computeProtocolMessage(refundTxn.sourceChain, 'r3', [targetOrder.id, orderTxn.id], 'Closed order');
1904
- try {
1905
- await this.execRefundTransaction(
1906
- refundTxn,
1907
- latestBlockTimestamp,
1908
- protocolMessage,
1909
- {type: 'r3', originOrderId: targetOrder.id, closerOrderId: orderTxn.id}
1910
- );
1911
- } catch (error) {
1912
- this.logger.error(
1913
- `Chain ${chainSymbol}: Failed to post multisig refund transaction for closed order ID ${
1914
- targetOrder.id
1915
- } to ${
1916
- targetOrder.sourceWalletAddress
1917
- } on chain ${
1918
- targetOrder.sourceChain
1919
- } because of error: ${
1920
- error.message
1921
- }`
1922
- );
1923
- }
1884
+ this.scheduleRefundTransaction(
1885
+ refundTxn,
1886
+ latestBlockTimestamp,
1887
+ protocolMessage,
1888
+ {type: 'r3', originOrderId: targetOrder.id, closerOrderId: orderTxn.id},
1889
+ `Chain ${chainSymbol}: Failed to post multisig refund transaction for closed order ID ${
1890
+ targetOrder.id
1891
+ } to ${
1892
+ targetOrder.sourceWalletAddress
1893
+ } on chain ${
1894
+ targetOrder.sourceChain
1895
+ }`
1896
+ );
1924
1897
  });
1925
1898
 
1926
- limitAndMarketOrders.forEach(async (orderTxn) => {
1899
+ limitAndMarketOrders.forEach((orderTxn) => {
1927
1900
  let result;
1928
1901
  try {
1929
1902
  result = this.tradeEngine.addOrder(orderTxn);
@@ -1950,7 +1923,7 @@ module.exports = class CapitaliskDEXModule {
1950
1923
 
1951
1924
  let makerCount = 0;
1952
1925
 
1953
- result.makers.forEach(async (makerOrder) => {
1926
+ result.makers.forEach((makerOrder) => {
1954
1927
  let makerChainOptions = this.options.chains[makerOrder.targetChain];
1955
1928
  let makerAddress = makerOrder.targetWalletAddress;
1956
1929
  let makerAmount = makerOrder.targetChain === this.baseChainSymbol ? makerOrder.lastValueTaken : makerOrder.lastSizeTaken;
@@ -1979,84 +1952,76 @@ module.exports = class CapitaliskDEXModule {
1979
1952
  [makerOrder.sourceChain, makerOrder.id, result.taker.id],
1980
1953
  'Order made'
1981
1954
  );
1982
- try {
1983
- await this.execMultisigTransaction(
1984
- makerOrder.targetChain,
1985
- makerTxn,
1986
- protocolMessage,
1987
- {type: 't2', originOrderId: makerOrder.id, makerOrderId: makerOrder.id, takerOrderId: result.taker.id}
1988
- );
1989
- } catch (error) {
1990
- this.logger.error(
1991
- `Chain ${chainSymbol}: Failed to post multisig transaction of maker ${makerAddress} on chain ${makerOrder.targetChain} because of error: ${error.message}`
1992
- );
1993
- }
1955
+ this.scheduleMultisigTransaction(
1956
+ makerOrder.targetChain,
1957
+ makerTxn,
1958
+ protocolMessage,
1959
+ {type: 't2', originOrderId: makerOrder.id, makerOrderId: makerOrder.id, takerOrderId: result.taker.id},
1960
+ `Chain ${chainSymbol}: Failed to post multisig transaction of maker ${makerAddress} on chain ${makerOrder.targetChain}`
1961
+ );
1994
1962
  });
1995
1963
 
1996
- (async () => {
1997
- if (!makerCount) {
1998
- return;
1999
- }
2000
- if (takerAmount <= 0n) {
2001
- this.logger.warn(
2002
- `Chain ${chainSymbol}: Did not post the taker trade order ${orderTxn.id} because the amount after fees was less than or equal to 0`
1964
+ if (makerCount) {
1965
+ if (takerAmount > 0n) {
1966
+ let takerTxn = {
1967
+ recipientAddress: takerAddress,
1968
+ amount: takerAmount.toString(),
1969
+ fee: takerChainOptions.exchangeFeeBase.toString(),
1970
+ timestamp: latestBlockTimestamp,
1971
+ height: latestChainHeights[takerTargetChain]
1972
+ };
1973
+ let protocolMessage = this._computeProtocolMessage(
1974
+ takerTargetChain,
1975
+ 't1',
1976
+ [result.taker.sourceChain, result.taker.id, makerCount],
1977
+ 'Orders taken'
2003
1978
  );
2004
- return;
2005
- }
2006
- let takerTxn = {
2007
- recipientAddress: takerAddress,
2008
- amount: takerAmount.toString(),
2009
- fee: takerChainOptions.exchangeFeeBase.toString(),
2010
- timestamp: latestBlockTimestamp,
2011
- height: latestChainHeights[takerTargetChain]
2012
- };
2013
- let protocolMessage = this._computeProtocolMessage(
2014
- takerTargetChain,
2015
- 't1',
2016
- [result.taker.sourceChain, result.taker.id, makerCount],
2017
- 'Orders taken'
2018
- );
2019
- try {
2020
- await this.execMultisigTransaction(
1979
+ this.scheduleMultisigTransaction(
2021
1980
  takerTargetChain,
2022
1981
  takerTxn,
2023
1982
  protocolMessage,
2024
- {type: 't1', originOrderId: result.taker.id, takerOrderId: result.taker.id, makerCount}
1983
+ {type: 't1', originOrderId: result.taker.id, takerOrderId: result.taker.id, makerCount},
1984
+ `Chain ${chainSymbol}: Failed to post multisig transaction of taker ${takerAddress} on chain ${takerTargetChain}`
2025
1985
  );
2026
- } catch (error) {
2027
- this.logger.error(
2028
- `Chain ${chainSymbol}: Failed to post multisig transaction of taker ${takerAddress} on chain ${takerTargetChain} because of error: ${error.message}`
1986
+ } else {
1987
+ this.logger.warn(
1988
+ `Chain ${chainSymbol}: Did not post the taker trade order ${orderTxn.id} because the amount after fees was less than or equal to 0`
2029
1989
  );
2030
1990
  }
2031
- })();
2032
-
2033
- (async () => {
2034
- if (orderTxn.type === 'market') {
2035
- let refundTxn = {
2036
- sourceChain: result.taker.sourceChain,
2037
- sourceWalletAddress: result.taker.sourceWalletAddress,
2038
- height: orderTxn.height
2039
- };
2040
- if (result.taker.sourceChain === this.baseChainSymbol) {
2041
- refundTxn.sourceChainAmount = result.taker.valueRemaining;
2042
- } else {
2043
- refundTxn.sourceChainAmount = result.taker.sizeRemaining;
2044
- }
2045
- if (refundTxn.sourceChainAmount <= 0n) {
2046
- return;
2047
- }
1991
+ }
1992
+
1993
+ if (orderTxn.type === 'market') {
1994
+ let refundTxn = {
1995
+ sourceChain: result.taker.sourceChain,
1996
+ sourceWalletAddress: result.taker.sourceWalletAddress,
1997
+ height: orderTxn.height
1998
+ };
1999
+ if (result.taker.sourceChain === this.baseChainSymbol) {
2000
+ refundTxn.sourceChainAmount = result.taker.valueRemaining;
2001
+ } else {
2002
+ refundTxn.sourceChainAmount = result.taker.sizeRemaining;
2003
+ }
2004
+ if (refundTxn.sourceChainAmount > 0n) {
2048
2005
  let protocolMessage = this._computeProtocolMessage(refundTxn.sourceChain, 'r4', [orderTxn.id], 'Unmatched market order part');
2049
- try {
2050
- await this.execRefundTransaction(refundTxn, latestBlockTimestamp, protocolMessage, {type: 'r4', originOrderId: orderTxn.id});
2051
- } catch (error) {
2052
- this.logger.error(
2053
- `Chain ${chainSymbol}: Failed to post multisig market order refund transaction of taker ${takerAddress} on chain ${takerTargetChain} because of error: ${error.message}`
2054
- );
2055
- }
2006
+ this.scheduleRefundTransaction(
2007
+ refundTxn,
2008
+ latestBlockTimestamp,
2009
+ protocolMessage,
2010
+ {type: 'r4', originOrderId: orderTxn.id},
2011
+ `Chain ${
2012
+ chainSymbol
2013
+ }: Failed to post multisig market order refund transaction of taker ${
2014
+ takerAddress
2015
+ } on chain ${
2016
+ takerTargetChain
2017
+ }`
2018
+ );
2056
2019
  }
2057
- })();
2020
+ }
2058
2021
  });
2059
2022
 
2023
+ await this.flushScheduledTransactions();
2024
+
2060
2025
  this.processedHeights = {...latestChainHeights};
2061
2026
  this.lastProcessedBlocks[blockData.chainSymbol] = blockData;
2062
2027
  }
@@ -2120,34 +2085,33 @@ module.exports = class CapitaliskDEXModule {
2120
2085
  fromHeight,
2121
2086
  toHeight
2122
2087
  });
2123
- await Promise.all(
2124
- dividendList.map(async (dividend) => {
2125
- let txnAmount = dividend.amount - BigInt(chainOptions.exchangeFeeBase);
2126
- if (txnAmount <= 0n) {
2127
- this.logger.debug(
2128
- `Chain ${chainSymbol}: Skipped dividend distribution to member address ${
2129
- dividend.walletAddress
2130
- } because the amount due after fees was less than or equal to 0`
2131
- );
2132
- return;
2133
- }
2134
- let dividendTxn = {
2135
- recipientAddress: dividend.walletAddress,
2136
- amount: txnAmount.toString(),
2137
- fee: chainOptions.exchangeFeeBase.toString(),
2138
- timestamp: latestBlockTimestamp,
2139
- height: chainHeight
2140
- };
2141
- let protocolMessage = this._computeProtocolMessage(chainSymbol, 'd1', [fromHeight + 1, toHeight], 'Member dividend');
2142
- try {
2143
- await this.execMultisigTransaction(chainSymbol, dividendTxn, protocolMessage);
2144
- } catch (error) {
2145
- this.logger.error(
2146
- `Chain ${chainSymbol}: Failed to post multisig dividend transaction to member address ${dividend.walletAddress} because of error: ${error.message}`
2147
- );
2148
- }
2149
- })
2150
- );
2088
+
2089
+ for (let dividend of dividendList) {
2090
+ let txnAmount = dividend.amount - BigInt(chainOptions.exchangeFeeBase);
2091
+ if (txnAmount <= 0n) {
2092
+ this.logger.debug(
2093
+ `Chain ${chainSymbol}: Skipped dividend distribution to member address ${
2094
+ dividend.walletAddress
2095
+ } because the amount due after fees was less than or equal to 0`
2096
+ );
2097
+ continue;
2098
+ }
2099
+ let dividendTxn = {
2100
+ recipientAddress: dividend.walletAddress,
2101
+ amount: txnAmount.toString(),
2102
+ fee: chainOptions.exchangeFeeBase.toString(),
2103
+ timestamp: latestBlockTimestamp,
2104
+ height: chainHeight
2105
+ };
2106
+ let protocolMessage = this._computeProtocolMessage(chainSymbol, 'd1', [fromHeight + 1, toHeight], 'Member dividend');
2107
+ this.scheduleMultisigTransaction(
2108
+ chainSymbol,
2109
+ dividendTxn,
2110
+ protocolMessage,
2111
+ null,
2112
+ `Chain ${chainSymbol}: Failed to post multisig dividend transaction to member address ${dividend.walletAddress}`
2113
+ );
2114
+ }
2151
2115
  };
2152
2116
 
2153
2117
  let baseChainForkTargetHeight = 0;
@@ -2638,37 +2602,36 @@ module.exports = class CapitaliskDEXModule {
2638
2602
  return block;
2639
2603
  }
2640
2604
 
2641
- async refundOrderBook(snapshot, timestamp, movedToAddresses) {
2605
+ scheduleRefundOrderBook(snapshot, timestamp, movedToAddresses) {
2642
2606
  let allOrders = snapshot.orderBook.bidLimitOrders.concat(snapshot.orderBook.askLimitOrders);
2643
- await Promise.all(
2644
- allOrders.map(async (order) => {
2645
- let movedToAddress = movedToAddresses[order.sourceChain];
2646
- if (movedToAddress) {
2647
- let protocolMessage = this._computeProtocolMessage(order.sourceChain, 'r5', [order.id, movedToAddress], 'DEX has moved');
2648
- await this.refundOrder(
2649
- order,
2650
- timestamp,
2651
- snapshot.chainHeights[order.sourceChain],
2652
- protocolMessage,
2653
- {type: 'r5', originOrderId: order.id}
2654
- );
2655
- } else {
2656
- let protocolMessage = this._computeProtocolMessage(order.sourceChain, 'r6', [order.id], 'DEX has been disabled');
2657
- allOrders.map(async (order) => {
2658
- await this.refundOrder(
2659
- order,
2660
- timestamp,
2661
- snapshot.chainHeights[order.sourceChain],
2662
- protocolMessage,
2663
- {type: 'r6', originOrderId: order.id}
2664
- );
2665
- })
2666
- }
2667
- })
2668
- );
2607
+ for (let order of allOrders) {
2608
+ let movedToAddress = movedToAddresses[order.sourceChain];
2609
+ let failureMessage = `Failed to post refund transaction for order ${order.id} as part of full order book refund`;
2610
+ if (movedToAddress) {
2611
+ let protocolMessage = this._computeProtocolMessage(order.sourceChain, 'r5', [order.id, movedToAddress], 'DEX has moved');
2612
+ this.scheduleRefundOrder(
2613
+ order,
2614
+ timestamp,
2615
+ snapshot.chainHeights[order.sourceChain],
2616
+ protocolMessage,
2617
+ {type: 'r5', originOrderId: order.id},
2618
+ failureMessage
2619
+ );
2620
+ } else {
2621
+ let protocolMessage = this._computeProtocolMessage(order.sourceChain, 'r6', [order.id], 'DEX has been disabled');
2622
+ this.scheduleRefundOrder(
2623
+ order,
2624
+ timestamp,
2625
+ snapshot.chainHeights[order.sourceChain],
2626
+ protocolMessage,
2627
+ {type: 'r6', originOrderId: order.id},
2628
+ failureMessage
2629
+ );
2630
+ }
2631
+ }
2669
2632
  }
2670
2633
 
2671
- async refundOrder(order, timestamp, refundHeight, reason, extraTransferData) {
2634
+ scheduleRefundOrder(order, timestamp, refundHeight, reason, extraTransferData, failureMessage) {
2672
2635
  let refundTxn = {
2673
2636
  sourceChain: order.sourceChain,
2674
2637
  sourceWalletAddress: order.sourceWalletAddress,
@@ -2679,7 +2642,7 @@ module.exports = class CapitaliskDEXModule {
2679
2642
  } else {
2680
2643
  refundTxn.sourceChainAmount = order.sizeRemaining;
2681
2644
  }
2682
- await this.execRefundTransaction(refundTxn, timestamp, reason, extraTransferData);
2645
+ this.scheduleRefundTransaction(refundTxn, timestamp, reason, extraTransferData, failureMessage);
2683
2646
  }
2684
2647
 
2685
2648
  _computeProtocolMessage(chainSymbol, code, args, reasonMessage) {
@@ -2696,15 +2659,16 @@ module.exports = class CapitaliskDEXModule {
2696
2659
  return messageParts.join(': ');
2697
2660
  }
2698
2661
 
2699
- async execRefundTransaction(txn, timestamp, reason, extraTransferData) {
2662
+ scheduleRefundTransaction(txn, timestamp, reason, extraTransferData, failureMessage) {
2700
2663
  let refundChainOptions = this.options.chains[txn.sourceChain];
2664
+ // Refunds do not charge the exchangeFeeRate.
2701
2665
  let refundAmount = txn.sourceChainAmount - BigInt(refundChainOptions.exchangeFeeBase);
2702
2666
 
2703
- // Refunds do not charge the exchangeFeeRate.
2704
2667
  if (refundAmount <= 0n) {
2705
- throw new Error(
2706
- 'Failed to make refund because amount was less than or equal to 0'
2668
+ this.logger.debug(
2669
+ `${failureMessage} because amount was less than or equal to 0`
2707
2670
  );
2671
+ return;
2708
2672
  }
2709
2673
 
2710
2674
  let refundTxn = {
@@ -2714,11 +2678,13 @@ module.exports = class CapitaliskDEXModule {
2714
2678
  timestamp,
2715
2679
  height: txn.height
2716
2680
  };
2717
- await this.execMultisigTransaction(
2681
+
2682
+ this.scheduleMultisigTransaction(
2718
2683
  txn.sourceChain,
2719
2684
  refundTxn,
2720
2685
  reason,
2721
- extraTransferData
2686
+ extraTransferData,
2687
+ failureMessage
2722
2688
  );
2723
2689
  }
2724
2690
 
@@ -2737,6 +2703,37 @@ module.exports = class CapitaliskDEXModule {
2737
2703
  }
2738
2704
  }
2739
2705
 
2706
+ scheduleMultisigTransaction(targetChain, transactionData, message, extraTransferData, failureMessage) {
2707
+ this.scheduledTransferInfos.push({
2708
+ targetChain,
2709
+ transactionData,
2710
+ message,
2711
+ extraTransferData,
2712
+ failureMessage
2713
+ });
2714
+ }
2715
+
2716
+ async flushScheduledTransactions() {
2717
+ for (let scheduledTransferInfo of this.scheduledTransferInfos) {
2718
+ let {
2719
+ targetChain,
2720
+ transactionData,
2721
+ message,
2722
+ extraTransferData,
2723
+ failureMessage
2724
+ } = scheduledTransferInfo;
2725
+
2726
+ try {
2727
+ await this.execMultisigTransaction(targetChain, transactionData, message, extraTransferData);
2728
+ } catch (error) {
2729
+ this.logger.debug(
2730
+ `${failureMessage} because of error: ${error.message}`
2731
+ );
2732
+ }
2733
+ }
2734
+ this.scheduledTransferInfos = [];
2735
+ }
2736
+
2740
2737
  async execMultisigTransaction(targetChain, transactionData, message, extraTransferData) {
2741
2738
  let chainTimestamp = this._denormalizeTimestamp(targetChain, transactionData.timestamp);
2742
2739
  let chainCrypto = this.chainCrypto[targetChain];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capitalisk-dex",
3
- "version": "17.3.1",
3
+ "version": "18.0.1",
4
4
  "description": "Decentralized exchange module.",
5
5
  "main": "index.js",
6
6
  "scripts": {