capitalisk-dex 18.3.1 → 18.3.3
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/LICENSE +661 -661
- package/README.md +104 -104
- package/big-int-calculator.js +30 -30
- package/index.js +17 -4
- package/package.json +1 -1
- package/test/trade-engine.js +563 -563
- package/trade-engine.js +416 -416
- package/utils.js +16 -16
package/README.md
CHANGED
|
@@ -1,104 +1,104 @@
|
|
|
1
|
-
# capitalisk-dex
|
|
2
|
-
Decentralized exchange module for the Capitalisk network.
|
|
3
|
-
|
|
4
|
-
## DEX protocol
|
|
5
|
-
|
|
6
|
-
### Actions
|
|
7
|
-
|
|
8
|
-
To send an order to the DEX, a user needs to send a regular transfer transaction to the DEX's multisignature wallet address with one of the following commands in the transaction's `data` field.
|
|
9
|
-
|
|
10
|
-
- **Limit order**: `${targetChain},limit,${bidOrAskPrice},${targetWalletAddress}`
|
|
11
|
-
- **Market order**: `${targetChain},market,${targetWalletAddress}`
|
|
12
|
-
- **Close order**: `${targetChain},close,${orderId}`
|
|
13
|
-
- **Credit**: `credit`
|
|
14
|
-
|
|
15
|
-
### Parameters
|
|
16
|
-
- **targetChain** is the symbol of the opposite blockchain within a given market (e.g. LSH)
|
|
17
|
-
- **bidOrAskPrice** is a limit order price.
|
|
18
|
-
- **targetWalletAddress** is the wallet address on the opposite blockchain where tokens should be sent to.
|
|
19
|
-
- **orderId** is the order ID (which matches the blockchain transaction ID).
|
|
20
|
-
|
|
21
|
-
When making a limit or a market order, the DEX will use the amount of the underlying transaction to calculate the quantity of counterparty tokens to acquire.
|
|
22
|
-
When performing a close order, the amount is not relevant; in this case, any amount can be specified as part of the close transaction (less is better); in any case, whatever amount is specified (minus blockchain transaction fees) will be refunded to the user's wallet via an `r3` refund transaction.
|
|
23
|
-
The credit action allows users to send tokens to the DEX wallet without triggering any operation.
|
|
24
|
-
|
|
25
|
-
### Responses
|
|
26
|
-
|
|
27
|
-
These status codes and messages appear in transactions created by the DEX (as part of the transaction `data` field):
|
|
28
|
-
|
|
29
|
-
**Refunds**
|
|
30
|
-
|
|
31
|
-
- `r1,${orderId}: Invalid order`
|
|
32
|
-
- `r2,${orderId}: Expired order`
|
|
33
|
-
- `r3,${orderId},${closeOrderId}: Closed order`
|
|
34
|
-
- `r4,${orderId}: Unmatched market order part`
|
|
35
|
-
- `r5,${orderId},${newWalletAddress}: DEX has moved`
|
|
36
|
-
- `r6,${orderId}: DEX has been disabled`
|
|
37
|
-
|
|
38
|
-
**Trades**
|
|
39
|
-
|
|
40
|
-
- `t1,${takerChain},${takerOrderId},${makerOrderCount}: Orders taken`
|
|
41
|
-
- `t2,${makerChain},${makerOrderId},${takerOrderId}: Order made`
|
|
42
|
-
|
|
43
|
-
- Taker is the account/wallet which takes the trade from someone else (from the maker).
|
|
44
|
-
- Maker provides tokens for someone else to take (to the taker).
|
|
45
|
-
- All market orders are takers.
|
|
46
|
-
- Pending limit orders in the order book will be makers.
|
|
47
|
-
- Limit orders can be makers or takers or both.
|
|
48
|
-
1. If a limit order is filled immediately as soon as placed, it is a taker.
|
|
49
|
-
2. If a limit order goes into pending state after placed, it will be a maker.
|
|
50
|
-
3. If a limit order is partially filled after it is placed, it is a taker; then the unfilled portion will be added to the order book and will be a maker.
|
|
51
|
-
- Takers are always matched against pending limit orders in the order book.
|
|
52
|
-
- t1 transaction represents money going into taker's wallet.
|
|
53
|
-
- t2 transaction represents money going into maker's wallet.
|
|
54
|
-
- t1 has **makerOrderCount** denoting number of makers it matched against from a single taker order.
|
|
55
|
-
- t2 is an individual maker transaction matched against a single taker order **takerOrderId**.
|
|
56
|
-
- For both market and limit orders there is always **1 t1** and **1-N t2** transactions.
|
|
57
|
-
|
|
58
|
-
**Dividends**
|
|
59
|
-
|
|
60
|
-
- `d1,${fromHeight},${toHeight}: Member dividend`
|
|
61
|
-
|
|
62
|
-
### Behaviors
|
|
63
|
-
|
|
64
|
-
- If the DEX does not recognize a command/order from a user (or it is invalid for whatever reason), it will send an `r1` refund transaction back to the user's wallet address which will return the full amount of the original transaction minus any blockchain transaction fees incurred by the DEX.
|
|
65
|
-
- A DEX adheres to a fixed order expiry. If an order expires before being filled or closed, the DEX will send an `r2` refund transaction back to the user's wallet address which will return the unfilled portion of the original transaction minus any blockchain transaction fees incurred by the DEX.
|
|
66
|
-
- If a pending limit order is closed by a user using a `close` action, the unfilled portion of the original order transaction amount (minus blockchain transaction fees) will be refunded back to the user's wallet address using an `r3` refund transaction. A user may only close their own orders.
|
|
67
|
-
- If a market order is made which cannot be completely filled by counterparty limit orders, then any unmatched part of the market order (minus blockchain transaction fees) will be refunded back to the user's wallet address as an `r4` refund transaction.
|
|
68
|
-
- If the majority of DEX operators have agreed to move the DEX to a new multisig wallet address, the DEX will issue a full refund (minus blockchain transaction fees) for every pending order and also every new order which is sent to the DEX wallet address thereafter via `r5` transactions. The DEX should keep refunding all transactions that are sent to the old address for at least 6 months in order to give clients enough time to update their caches to point to the new address.
|
|
69
|
-
- If the majority of DEX operators have agreed to shut down the DEX, the DEX will issue a full refund (minus blockchain transaction fees) for every pending order and also every new order which is sent to the DEX wallet address thereafter via `r6` transactions. The DEX should keep refunding transactions sent to the last active address for at least 6 months to give clients enough time to update their caches to point to a different DEX. In practice, a DEX should not shut down because it does not align with financial incentives and it requires a high degree of coordination between members but this refund type exists anyway to account for unusual scenarios and use cases.
|
|
70
|
-
- In addition to basic blockchain fees, a DEX can charge an exchange fee as a percentage of the order value. All DEX members/nodes need to agree on the same percentage fee.
|
|
71
|
-
|
|
72
|
-
### Short protocol
|
|
73
|
-
|
|
74
|
-
- For trades and refunds, only the first part of message is mandatory, the part which begins with the column character is optional depending on the market implementation.
|
|
75
|
-
- If one of the blockchains involved in a market does not provide sufficient space in a transaction to store a full protocol message, order IDs and wallet addresses may be trimmed down to fit within the available space.
|
|
76
|
-
|
|
77
|
-
### Scope
|
|
78
|
-
|
|
79
|
-
This project is intended to be simple. Fewer lines of code and fewer dependencies means more security.
|
|
80
|
-
If additional features want to be added beyond the current feature set (e.g. such as loans, NFTs, liquidity pools and alternative matching engines), this project should be forked into a separate project 'distro'.
|
|
81
|
-
|
|
82
|
-
### Sponsors
|
|
83
|
-
|
|
84
|
-
Special thanks to Carolina delegate for being an early sponsor of this project.
|
|
85
|
-
|
|
86
|
-
## License
|
|
87
|
-
|
|
88
|
-
This product is issued under the AGPL v3 license with a potential copyleft exemption.
|
|
89
|
-
|
|
90
|
-
### AGPL by default
|
|
91
|
-
|
|
92
|
-
By default, this product is issued under `AGPL-3.0`.
|
|
93
|
-
|
|
94
|
-
### Copyleft exemption for CLSK token holders
|
|
95
|
-
|
|
96
|
-
If you own `100K CLSK` tokens (https://capitalisk.com/), then you are exempt from the AGPL copyleft requirement of making the code of your derived projects public. This exemption applies automatically from the moment that you acquire 100K or more CLSK tokens and it is valid so long as you continue to hold that amount of tokens.
|
|
97
|
-
|
|
98
|
-
If your CLSK balance falls below 100K, then you will be once again bound to the copyleft conditions of AGPL-3.0 after a grace period of 90 days; after this grace period, your derived project's code must be made public. Timestamps which can be used to prove ownership of CLSK tokens over time are recorded on the Capitalisk blockchain in a decentralized, immutable way so it is important that you hold 100K CLSK throughout your derived project's entire commercial life if you intend to keep the code private.
|
|
99
|
-
|
|
100
|
-
This exemption also applies to companies; in this case, the total CLSK holdings of the company plus those of its directors and board members must be greater than 100K multiplied by the maximum number of contributors which have worked on the project concurrently since the start of the project (e.g. according to records in the project's code repository). If a company falls out of compliance, the standard 90-day grace period applies before reverting back to the AGPL-3.0 license.
|
|
101
|
-
|
|
102
|
-
Derived code may optionally be distributed with the same copyleft exemption clause as this project; in this case, the CLSK token ownership requirement must be at least as high as this project.
|
|
103
|
-
|
|
104
|
-
The amount of CLSK tokens which need to be held to qualify for the copyleft exemption may be revised downwards in the future but never upwards.
|
|
1
|
+
# capitalisk-dex
|
|
2
|
+
Decentralized exchange module for the Capitalisk network.
|
|
3
|
+
|
|
4
|
+
## DEX protocol
|
|
5
|
+
|
|
6
|
+
### Actions
|
|
7
|
+
|
|
8
|
+
To send an order to the DEX, a user needs to send a regular transfer transaction to the DEX's multisignature wallet address with one of the following commands in the transaction's `data` field.
|
|
9
|
+
|
|
10
|
+
- **Limit order**: `${targetChain},limit,${bidOrAskPrice},${targetWalletAddress}`
|
|
11
|
+
- **Market order**: `${targetChain},market,${targetWalletAddress}`
|
|
12
|
+
- **Close order**: `${targetChain},close,${orderId}`
|
|
13
|
+
- **Credit**: `credit`
|
|
14
|
+
|
|
15
|
+
### Parameters
|
|
16
|
+
- **targetChain** is the symbol of the opposite blockchain within a given market (e.g. LSH)
|
|
17
|
+
- **bidOrAskPrice** is a limit order price.
|
|
18
|
+
- **targetWalletAddress** is the wallet address on the opposite blockchain where tokens should be sent to.
|
|
19
|
+
- **orderId** is the order ID (which matches the blockchain transaction ID).
|
|
20
|
+
|
|
21
|
+
When making a limit or a market order, the DEX will use the amount of the underlying transaction to calculate the quantity of counterparty tokens to acquire.
|
|
22
|
+
When performing a close order, the amount is not relevant; in this case, any amount can be specified as part of the close transaction (less is better); in any case, whatever amount is specified (minus blockchain transaction fees) will be refunded to the user's wallet via an `r3` refund transaction.
|
|
23
|
+
The credit action allows users to send tokens to the DEX wallet without triggering any operation.
|
|
24
|
+
|
|
25
|
+
### Responses
|
|
26
|
+
|
|
27
|
+
These status codes and messages appear in transactions created by the DEX (as part of the transaction `data` field):
|
|
28
|
+
|
|
29
|
+
**Refunds**
|
|
30
|
+
|
|
31
|
+
- `r1,${orderId}: Invalid order`
|
|
32
|
+
- `r2,${orderId}: Expired order`
|
|
33
|
+
- `r3,${orderId},${closeOrderId}: Closed order`
|
|
34
|
+
- `r4,${orderId}: Unmatched market order part`
|
|
35
|
+
- `r5,${orderId},${newWalletAddress}: DEX has moved`
|
|
36
|
+
- `r6,${orderId}: DEX has been disabled`
|
|
37
|
+
|
|
38
|
+
**Trades**
|
|
39
|
+
|
|
40
|
+
- `t1,${takerChain},${takerOrderId},${makerOrderCount}: Orders taken`
|
|
41
|
+
- `t2,${makerChain},${makerOrderId},${takerOrderId}: Order made`
|
|
42
|
+
|
|
43
|
+
- Taker is the account/wallet which takes the trade from someone else (from the maker).
|
|
44
|
+
- Maker provides tokens for someone else to take (to the taker).
|
|
45
|
+
- All market orders are takers.
|
|
46
|
+
- Pending limit orders in the order book will be makers.
|
|
47
|
+
- Limit orders can be makers or takers or both.
|
|
48
|
+
1. If a limit order is filled immediately as soon as placed, it is a taker.
|
|
49
|
+
2. If a limit order goes into pending state after placed, it will be a maker.
|
|
50
|
+
3. If a limit order is partially filled after it is placed, it is a taker; then the unfilled portion will be added to the order book and will be a maker.
|
|
51
|
+
- Takers are always matched against pending limit orders in the order book.
|
|
52
|
+
- t1 transaction represents money going into taker's wallet.
|
|
53
|
+
- t2 transaction represents money going into maker's wallet.
|
|
54
|
+
- t1 has **makerOrderCount** denoting number of makers it matched against from a single taker order.
|
|
55
|
+
- t2 is an individual maker transaction matched against a single taker order **takerOrderId**.
|
|
56
|
+
- For both market and limit orders there is always **1 t1** and **1-N t2** transactions.
|
|
57
|
+
|
|
58
|
+
**Dividends**
|
|
59
|
+
|
|
60
|
+
- `d1,${fromHeight},${toHeight}: Member dividend`
|
|
61
|
+
|
|
62
|
+
### Behaviors
|
|
63
|
+
|
|
64
|
+
- If the DEX does not recognize a command/order from a user (or it is invalid for whatever reason), it will send an `r1` refund transaction back to the user's wallet address which will return the full amount of the original transaction minus any blockchain transaction fees incurred by the DEX.
|
|
65
|
+
- A DEX adheres to a fixed order expiry. If an order expires before being filled or closed, the DEX will send an `r2` refund transaction back to the user's wallet address which will return the unfilled portion of the original transaction minus any blockchain transaction fees incurred by the DEX.
|
|
66
|
+
- If a pending limit order is closed by a user using a `close` action, the unfilled portion of the original order transaction amount (minus blockchain transaction fees) will be refunded back to the user's wallet address using an `r3` refund transaction. A user may only close their own orders.
|
|
67
|
+
- If a market order is made which cannot be completely filled by counterparty limit orders, then any unmatched part of the market order (minus blockchain transaction fees) will be refunded back to the user's wallet address as an `r4` refund transaction.
|
|
68
|
+
- If the majority of DEX operators have agreed to move the DEX to a new multisig wallet address, the DEX will issue a full refund (minus blockchain transaction fees) for every pending order and also every new order which is sent to the DEX wallet address thereafter via `r5` transactions. The DEX should keep refunding all transactions that are sent to the old address for at least 6 months in order to give clients enough time to update their caches to point to the new address.
|
|
69
|
+
- If the majority of DEX operators have agreed to shut down the DEX, the DEX will issue a full refund (minus blockchain transaction fees) for every pending order and also every new order which is sent to the DEX wallet address thereafter via `r6` transactions. The DEX should keep refunding transactions sent to the last active address for at least 6 months to give clients enough time to update their caches to point to a different DEX. In practice, a DEX should not shut down because it does not align with financial incentives and it requires a high degree of coordination between members but this refund type exists anyway to account for unusual scenarios and use cases.
|
|
70
|
+
- In addition to basic blockchain fees, a DEX can charge an exchange fee as a percentage of the order value. All DEX members/nodes need to agree on the same percentage fee.
|
|
71
|
+
|
|
72
|
+
### Short protocol
|
|
73
|
+
|
|
74
|
+
- For trades and refunds, only the first part of message is mandatory, the part which begins with the column character is optional depending on the market implementation.
|
|
75
|
+
- If one of the blockchains involved in a market does not provide sufficient space in a transaction to store a full protocol message, order IDs and wallet addresses may be trimmed down to fit within the available space.
|
|
76
|
+
|
|
77
|
+
### Scope
|
|
78
|
+
|
|
79
|
+
This project is intended to be simple. Fewer lines of code and fewer dependencies means more security.
|
|
80
|
+
If additional features want to be added beyond the current feature set (e.g. such as loans, NFTs, liquidity pools and alternative matching engines), this project should be forked into a separate project 'distro'.
|
|
81
|
+
|
|
82
|
+
### Sponsors
|
|
83
|
+
|
|
84
|
+
Special thanks to Carolina delegate for being an early sponsor of this project.
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
This product is issued under the AGPL v3 license with a potential copyleft exemption.
|
|
89
|
+
|
|
90
|
+
### AGPL by default
|
|
91
|
+
|
|
92
|
+
By default, this product is issued under `AGPL-3.0`.
|
|
93
|
+
|
|
94
|
+
### Copyleft exemption for CLSK token holders
|
|
95
|
+
|
|
96
|
+
If you own `100K CLSK` tokens (https://capitalisk.com/), then you are exempt from the AGPL copyleft requirement of making the code of your derived projects public. This exemption applies automatically from the moment that you acquire 100K or more CLSK tokens and it is valid so long as you continue to hold that amount of tokens.
|
|
97
|
+
|
|
98
|
+
If your CLSK balance falls below 100K, then you will be once again bound to the copyleft conditions of AGPL-3.0 after a grace period of 90 days; after this grace period, your derived project's code must be made public. Timestamps which can be used to prove ownership of CLSK tokens over time are recorded on the Capitalisk blockchain in a decentralized, immutable way so it is important that you hold 100K CLSK throughout your derived project's entire commercial life if you intend to keep the code private.
|
|
99
|
+
|
|
100
|
+
This exemption also applies to companies; in this case, the total CLSK holdings of the company plus those of its directors and board members must be greater than 100K multiplied by the maximum number of contributors which have worked on the project concurrently since the start of the project (e.g. according to records in the project's code repository). If a company falls out of compliance, the standard 90-day grace period applies before reverting back to the AGPL-3.0 license.
|
|
101
|
+
|
|
102
|
+
Derived code may optionally be distributed with the same copyleft exemption clause as this project; in this case, the CLSK token ownership requirement must be at least as high as this project.
|
|
103
|
+
|
|
104
|
+
The amount of CLSK tokens which need to be held to qualify for the copyleft exemption may be revised downwards in the future but never upwards.
|
package/big-int-calculator.js
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
const DEFAULT_DECIMAL_PRECISION = 4;
|
|
2
|
-
|
|
3
|
-
class BigIntCalculator {
|
|
4
|
-
constructor(options) {
|
|
5
|
-
options = options || {};
|
|
6
|
-
this.decimalPrecision = options.decimalPrecision == null ?
|
|
7
|
-
DEFAULT_DECIMAL_PRECISION : options.decimalPrecision;
|
|
8
|
-
this.decimalPrecisionFactor = 10 ** this.decimalPrecision;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
multiplyBigIntByDecimal(bigIntValue, decimalValue) {
|
|
12
|
-
return bigIntValue * BigInt(Math.round(decimalValue * this.decimalPrecisionFactor)) / BigInt(this.decimalPrecisionFactor);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
divideBigIntByDecimal(bigIntValue, decimalValue) {
|
|
16
|
-
if (decimalValue === 0) {
|
|
17
|
-
return NaN;
|
|
18
|
-
}
|
|
19
|
-
return bigIntValue * BigInt(this.decimalPrecisionFactor) / BigInt(Math.round(decimalValue * this.decimalPrecisionFactor));
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
divideBigIntByBigInt(bigIntValueA, bigIntValueB) {
|
|
23
|
-
if (bigIntValueB === 0n) {
|
|
24
|
-
return NaN;
|
|
25
|
-
}
|
|
26
|
-
return Math.round(Number(bigIntValueA * BigInt(this.decimalPrecisionFactor * 10) / bigIntValueB) / 10) / this.decimalPrecisionFactor;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
module.exports = BigIntCalculator;
|
|
1
|
+
const DEFAULT_DECIMAL_PRECISION = 4;
|
|
2
|
+
|
|
3
|
+
class BigIntCalculator {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
options = options || {};
|
|
6
|
+
this.decimalPrecision = options.decimalPrecision == null ?
|
|
7
|
+
DEFAULT_DECIMAL_PRECISION : options.decimalPrecision;
|
|
8
|
+
this.decimalPrecisionFactor = 10 ** this.decimalPrecision;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
multiplyBigIntByDecimal(bigIntValue, decimalValue) {
|
|
12
|
+
return bigIntValue * BigInt(Math.round(decimalValue * this.decimalPrecisionFactor)) / BigInt(this.decimalPrecisionFactor);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
divideBigIntByDecimal(bigIntValue, decimalValue) {
|
|
16
|
+
if (decimalValue === 0) {
|
|
17
|
+
return NaN;
|
|
18
|
+
}
|
|
19
|
+
return bigIntValue * BigInt(this.decimalPrecisionFactor) / BigInt(Math.round(decimalValue * this.decimalPrecisionFactor));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
divideBigIntByBigInt(bigIntValueA, bigIntValueB) {
|
|
23
|
+
if (bigIntValueB === 0n) {
|
|
24
|
+
return NaN;
|
|
25
|
+
}
|
|
26
|
+
return Math.round(Number(bigIntValueA * BigInt(this.decimalPrecisionFactor * 10) / bigIntValueB) / 10) / this.decimalPrecisionFactor;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = BigIntCalculator;
|
package/index.js
CHANGED
|
@@ -977,7 +977,6 @@ module.exports = class CapitaliskDEXModule {
|
|
|
977
977
|
let baseChainReadMaxTransactions = baseChainOptions.readMaxTransactions == null ? tradeHistorySize : baseChainOptions.readMaxTransactions;
|
|
978
978
|
let quoteChainReadMaxTransactions = quoteChainOptions.readMaxTransactions == null ? tradeHistorySize : quoteChainOptions.readMaxTransactions;
|
|
979
979
|
|
|
980
|
-
let historyStartTimestamp = this.options.tradeHistoryStartTimestamp == null ? 0 : this.options.tradeHistoryStartTimestamp;
|
|
981
980
|
if (this.latestBasePriceTimestamp == null) {
|
|
982
981
|
this.latestBasePriceTimestamp = this.options.tradeHistoryStartTimestamp == null ? 0 :
|
|
983
982
|
this._denormalizeTimestamp(this.baseChainSymbol, this.options.tradeHistoryStartTimestamp);
|
|
@@ -1061,7 +1060,7 @@ module.exports = class CapitaliskDEXModule {
|
|
|
1061
1060
|
|
|
1062
1061
|
let priceHistory = [];
|
|
1063
1062
|
|
|
1064
|
-
// Filter out all entries which are
|
|
1063
|
+
// Filter out all entries which are incomplete.
|
|
1065
1064
|
let txnPairsList = Object.values(txnPairsMap).filter((txnPair) => {
|
|
1066
1065
|
let firstBaseTxn = txnPair.base[0];
|
|
1067
1066
|
let firstQuoteTxn = txnPair.quote[0];
|
|
@@ -1125,11 +1124,27 @@ module.exports = class CapitaliskDEXModule {
|
|
|
1125
1124
|
|
|
1126
1125
|
if (baseChainTxns.length) {
|
|
1127
1126
|
let lastBaseChainTxn = baseChainTxns[baseChainTxns.length - 1];
|
|
1127
|
+
let prevLatestBasePriceTimestamp = this.latestBasePriceTimestamp;
|
|
1128
1128
|
this.latestBasePriceTimestamp = lastBaseChainTxn.timestamp;
|
|
1129
|
+
if (this.latestBasePriceTimestamp === prevLatestBasePriceTimestamp) {
|
|
1130
|
+
// If the latest base timestamp is the same as before, then force increment to ensure that
|
|
1131
|
+
// the price history always progresses including in situations where many transactions
|
|
1132
|
+
// have the same timestamp; in such cases, the price at that specific timestamp will be
|
|
1133
|
+
// based on a sample.
|
|
1134
|
+
this.latestBasePriceTimestamp++;
|
|
1135
|
+
}
|
|
1129
1136
|
}
|
|
1130
1137
|
if (quoteChainTxns.length) {
|
|
1131
1138
|
let lastQuoteChainTxn = quoteChainTxns[quoteChainTxns.length - 1];
|
|
1139
|
+
let prevLatestQuotePriceTimestamp = this.latestQuotePriceTimestamp;
|
|
1132
1140
|
this.latestQuotePriceTimestamp = lastQuoteChainTxn.timestamp;
|
|
1141
|
+
if (this.latestQuotePriceTimestamp === prevLatestQuotePriceTimestamp) {
|
|
1142
|
+
// If the latest quote timestamp is the same as before, then force increment to ensure that
|
|
1143
|
+
// the price history always progresses including in situations where many transactions
|
|
1144
|
+
// have the same timestamp; in such cases, the price at that specific timestamp will be
|
|
1145
|
+
// based on a sample.
|
|
1146
|
+
this.latestQuotePriceTimestamp++;
|
|
1147
|
+
}
|
|
1133
1148
|
}
|
|
1134
1149
|
|
|
1135
1150
|
let unprocessedBaseExpiry = this._normalizeTimestamp(this.baseChainSymbol, lastBaseEntryTimestamp) - this.options.tradeHistoryUnprocessedTransactionExpiry;
|
|
@@ -2527,8 +2542,6 @@ module.exports = class CapitaliskDEXModule {
|
|
|
2527
2542
|
a.id
|
|
2528
2543
|
} and ${
|
|
2529
2544
|
b.id
|
|
2530
|
-
} from block ID ${
|
|
2531
|
-
blockId
|
|
2532
2545
|
} because they had the same sortKey - This may lead to nondeterministic output`
|
|
2533
2546
|
);
|
|
2534
2547
|
return 0;
|