@lightconexyz/lightcone-sdk 0.5.2 → 0.7.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.
Files changed (228) hide show
  1. package/README.md +39 -5
  2. package/dist/auth/client.d.ts.map +1 -1
  3. package/dist/auth/client.js +2 -0
  4. package/dist/auth/client.js.map +1 -1
  5. package/dist/auth/index.d.ts +15 -0
  6. package/dist/auth/index.d.ts.map +1 -1
  7. package/dist/auth/index.js +10 -1
  8. package/dist/auth/index.js.map +1 -1
  9. package/dist/client.d.ts +43 -4
  10. package/dist/client.d.ts.map +1 -1
  11. package/dist/client.js +70 -9
  12. package/dist/client.js.map +1 -1
  13. package/dist/context.d.ts +7 -1
  14. package/dist/context.d.ts.map +1 -1
  15. package/dist/context.js +60 -6
  16. package/dist/context.js.map +1 -1
  17. package/dist/domain/admin/client.d.ts +21 -2
  18. package/dist/domain/admin/client.d.ts.map +1 -1
  19. package/dist/domain/admin/client.js +90 -4
  20. package/dist/domain/admin/client.js.map +1 -1
  21. package/dist/domain/admin/wire.d.ts +292 -7
  22. package/dist/domain/admin/wire.d.ts.map +1 -1
  23. package/dist/domain/admin/wire.js.map +1 -1
  24. package/dist/domain/faucet.d.ts +25 -0
  25. package/dist/domain/faucet.d.ts.map +1 -0
  26. package/dist/domain/faucet.js +3 -0
  27. package/dist/domain/faucet.js.map +1 -0
  28. package/dist/domain/index.d.ts +2 -0
  29. package/dist/domain/index.d.ts.map +1 -1
  30. package/dist/domain/index.js +3 -1
  31. package/dist/domain/index.js.map +1 -1
  32. package/dist/domain/market/client.d.ts +23 -2
  33. package/dist/domain/market/client.d.ts.map +1 -1
  34. package/dist/domain/market/client.js +31 -1
  35. package/dist/domain/market/client.js.map +1 -1
  36. package/dist/domain/market/convert.d.ts +10 -0
  37. package/dist/domain/market/convert.d.ts.map +1 -1
  38. package/dist/domain/market/convert.js +44 -5
  39. package/dist/domain/market/convert.js.map +1 -1
  40. package/dist/domain/market/icon.d.ts +17 -0
  41. package/dist/domain/market/icon.d.ts.map +1 -0
  42. package/dist/domain/market/icon.js +25 -0
  43. package/dist/domain/market/icon.js.map +1 -0
  44. package/dist/domain/market/index.d.ts +21 -5
  45. package/dist/domain/market/index.d.ts.map +1 -1
  46. package/dist/domain/market/index.js +15 -1
  47. package/dist/domain/market/index.js.map +1 -1
  48. package/dist/domain/market/outcome.d.ts +4 -1
  49. package/dist/domain/market/outcome.d.ts.map +1 -1
  50. package/dist/domain/market/outcome.js +8 -7
  51. package/dist/domain/market/outcome.js.map +1 -1
  52. package/dist/domain/market/tokens.d.ts +55 -3
  53. package/dist/domain/market/tokens.d.ts.map +1 -1
  54. package/dist/domain/market/tokens.js +105 -9
  55. package/dist/domain/market/tokens.js.map +1 -1
  56. package/dist/domain/market/wire.d.ts +69 -10
  57. package/dist/domain/market/wire.d.ts.map +1 -1
  58. package/dist/domain/market/wire.js +5 -0
  59. package/dist/domain/market/wire.js.map +1 -1
  60. package/dist/domain/metrics/client.d.ts +66 -0
  61. package/dist/domain/metrics/client.d.ts.map +1 -0
  62. package/dist/domain/metrics/client.js +124 -0
  63. package/dist/domain/metrics/client.js.map +1 -0
  64. package/dist/domain/metrics/index.d.ts +3 -0
  65. package/dist/domain/metrics/index.d.ts.map +1 -0
  66. package/dist/domain/metrics/index.js +19 -0
  67. package/dist/domain/metrics/index.js.map +1 -0
  68. package/dist/domain/metrics/wire.d.ts +346 -0
  69. package/dist/domain/metrics/wire.d.ts.map +1 -0
  70. package/dist/domain/metrics/wire.js +3 -0
  71. package/dist/domain/metrics/wire.js.map +1 -0
  72. package/dist/domain/notification/client.d.ts +6 -0
  73. package/dist/domain/notification/client.d.ts.map +1 -1
  74. package/dist/domain/notification/client.js +10 -0
  75. package/dist/domain/notification/client.js.map +1 -1
  76. package/dist/domain/notification/index.d.ts +6 -2
  77. package/dist/domain/notification/index.d.ts.map +1 -1
  78. package/dist/domain/notification/index.js.map +1 -1
  79. package/dist/domain/order/client.d.ts +34 -6
  80. package/dist/domain/order/client.d.ts.map +1 -1
  81. package/dist/domain/order/client.js +88 -21
  82. package/dist/domain/order/client.js.map +1 -1
  83. package/dist/domain/order/convert.d.ts +5 -5
  84. package/dist/domain/order/convert.d.ts.map +1 -1
  85. package/dist/domain/order/convert.js +3 -3
  86. package/dist/domain/order/convert.js.map +1 -1
  87. package/dist/domain/order/index.d.ts +3 -2
  88. package/dist/domain/order/index.d.ts.map +1 -1
  89. package/dist/domain/order/index.js +11 -3
  90. package/dist/domain/order/index.js.map +1 -1
  91. package/dist/domain/order/state.d.ts +9 -7
  92. package/dist/domain/order/state.d.ts.map +1 -1
  93. package/dist/domain/order/state.js +81 -28
  94. package/dist/domain/order/state.js.map +1 -1
  95. package/dist/domain/orderbook/client.d.ts +6 -2
  96. package/dist/domain/orderbook/client.d.ts.map +1 -1
  97. package/dist/domain/orderbook/client.js +17 -0
  98. package/dist/domain/orderbook/client.js.map +1 -1
  99. package/dist/domain/orderbook/index.d.ts +1 -1
  100. package/dist/domain/orderbook/index.d.ts.map +1 -1
  101. package/dist/domain/orderbook/index.js +3 -8
  102. package/dist/domain/orderbook/index.js.map +1 -1
  103. package/dist/domain/orderbook/state.d.ts +30 -7
  104. package/dist/domain/orderbook/state.d.ts.map +1 -1
  105. package/dist/domain/orderbook/state.js +41 -12
  106. package/dist/domain/orderbook/state.js.map +1 -1
  107. package/dist/domain/position/builders.d.ts +11 -8
  108. package/dist/domain/position/builders.d.ts.map +1 -1
  109. package/dist/domain/position/builders.js +31 -25
  110. package/dist/domain/position/builders.js.map +1 -1
  111. package/dist/domain/position/client.d.ts +66 -5
  112. package/dist/domain/position/client.d.ts.map +1 -1
  113. package/dist/domain/position/client.js +101 -9
  114. package/dist/domain/position/client.js.map +1 -1
  115. package/dist/domain/position/index.d.ts +3 -2
  116. package/dist/domain/position/index.d.ts.map +1 -1
  117. package/dist/domain/position/index.js.map +1 -1
  118. package/dist/domain/price_history/client.d.ts +12 -1
  119. package/dist/domain/price_history/client.d.ts.map +1 -1
  120. package/dist/domain/price_history/client.js +14 -0
  121. package/dist/domain/price_history/client.js.map +1 -1
  122. package/dist/domain/price_history/wire.d.ts +27 -0
  123. package/dist/domain/price_history/wire.d.ts.map +1 -1
  124. package/dist/domain/price_history/wire.js.map +1 -1
  125. package/dist/domain/referral/client.d.ts +6 -0
  126. package/dist/domain/referral/client.d.ts.map +1 -1
  127. package/dist/domain/referral/client.js +22 -9
  128. package/dist/domain/referral/client.js.map +1 -1
  129. package/dist/domain/trade/client.d.ts +1 -0
  130. package/dist/domain/trade/client.d.ts.map +1 -1
  131. package/dist/domain/trade/client.js +14 -0
  132. package/dist/domain/trade/client.js.map +1 -1
  133. package/dist/domain/trade/wire.d.ts +6 -0
  134. package/dist/domain/trade/wire.d.ts.map +1 -1
  135. package/dist/domain/trade/wire.js.map +1 -1
  136. package/dist/env.d.ts +6 -1
  137. package/dist/env.d.ts.map +1 -1
  138. package/dist/env.js +19 -9
  139. package/dist/env.js.map +1 -1
  140. package/dist/http/client.d.ts +9 -0
  141. package/dist/http/client.d.ts.map +1 -1
  142. package/dist/http/client.js +29 -11
  143. package/dist/http/client.js.map +1 -1
  144. package/dist/index.d.ts +2 -2
  145. package/dist/index.d.ts.map +1 -1
  146. package/dist/index.js.map +1 -1
  147. package/dist/prelude.d.ts +16 -7
  148. package/dist/prelude.d.ts.map +1 -1
  149. package/dist/prelude.js +10 -7
  150. package/dist/prelude.js.map +1 -1
  151. package/dist/privy/index.d.ts +1 -1
  152. package/dist/privy/index.js.map +1 -1
  153. package/dist/program/accounts.d.ts +12 -7
  154. package/dist/program/accounts.d.ts.map +1 -1
  155. package/dist/program/accounts.js +38 -16
  156. package/dist/program/accounts.js.map +1 -1
  157. package/dist/program/builder.d.ts +0 -4
  158. package/dist/program/builder.d.ts.map +1 -1
  159. package/dist/program/builder.js +0 -8
  160. package/dist/program/builder.js.map +1 -1
  161. package/dist/program/constants.d.ts +20 -7
  162. package/dist/program/constants.d.ts.map +1 -1
  163. package/dist/program/constants.js +21 -8
  164. package/dist/program/constants.js.map +1 -1
  165. package/dist/program/error.d.ts +25 -1
  166. package/dist/program/error.d.ts.map +1 -1
  167. package/dist/program/error.js +72 -0
  168. package/dist/program/error.js.map +1 -1
  169. package/dist/program/index.d.ts +7 -7
  170. package/dist/program/index.d.ts.map +1 -1
  171. package/dist/program/index.js +36 -9
  172. package/dist/program/index.js.map +1 -1
  173. package/dist/program/instructions.d.ts +184 -71
  174. package/dist/program/instructions.d.ts.map +1 -1
  175. package/dist/program/instructions.js +573 -140
  176. package/dist/program/instructions.js.map +1 -1
  177. package/dist/program/orders.js +2 -2
  178. package/dist/program/orders.js.map +1 -1
  179. package/dist/program/pda.d.ts +21 -3
  180. package/dist/program/pda.d.ts.map +1 -1
  181. package/dist/program/pda.js +43 -6
  182. package/dist/program/pda.js.map +1 -1
  183. package/dist/program/types.d.ts +139 -21
  184. package/dist/program/types.d.ts.map +1 -1
  185. package/dist/program/types.js.map +1 -1
  186. package/dist/program/utils.d.ts +31 -2
  187. package/dist/program/utils.d.ts.map +1 -1
  188. package/dist/program/utils.js +132 -5
  189. package/dist/program/utils.js.map +1 -1
  190. package/dist/rpc.d.ts +6 -1
  191. package/dist/rpc.d.ts.map +1 -1
  192. package/dist/rpc.js +9 -7
  193. package/dist/rpc.js.map +1 -1
  194. package/dist/rpcFailover.d.ts +22 -0
  195. package/dist/rpcFailover.d.ts.map +1 -0
  196. package/dist/rpcFailover.js +71 -0
  197. package/dist/rpcFailover.js.map +1 -0
  198. package/dist/shared/fmt/constants.d.ts +5 -0
  199. package/dist/shared/fmt/constants.d.ts.map +1 -0
  200. package/dist/shared/fmt/constants.js +25 -0
  201. package/dist/shared/fmt/constants.js.map +1 -0
  202. package/dist/shared/fmt/decimal.d.ts +7 -0
  203. package/dist/shared/fmt/decimal.d.ts.map +1 -1
  204. package/dist/shared/fmt/decimal.js +32 -24
  205. package/dist/shared/fmt/decimal.js.map +1 -1
  206. package/dist/shared/fmt/num.d.ts +7 -0
  207. package/dist/shared/fmt/num.d.ts.map +1 -1
  208. package/dist/shared/fmt/num.js +27 -15
  209. package/dist/shared/fmt/num.js.map +1 -1
  210. package/dist/shared/index.d.ts +1 -1
  211. package/dist/shared/index.d.ts.map +1 -1
  212. package/dist/shared/index.js +2 -1
  213. package/dist/shared/index.js.map +1 -1
  214. package/dist/shared/types.d.ts +1 -0
  215. package/dist/shared/types.d.ts.map +1 -1
  216. package/dist/shared/types.js +19 -0
  217. package/dist/shared/types.js.map +1 -1
  218. package/dist/ws/client.node.js +1 -1
  219. package/dist/ws/client.node.js.map +1 -1
  220. package/dist/ws/index.d.ts +12 -1
  221. package/dist/ws/index.d.ts.map +1 -1
  222. package/dist/ws/index.js +20 -0
  223. package/dist/ws/index.js.map +1 -1
  224. package/dist/ws/subscriptions.d.ts +6 -0
  225. package/dist/ws/subscriptions.d.ts.map +1 -1
  226. package/dist/ws/subscriptions.js +4 -0
  227. package/dist/ws/subscriptions.js.map +1 -1
  228. package/package.json +1 -1
@@ -1,69 +1,103 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.UserTriggerOrders = exports.UserOpenOrders = void 0;
3
+ exports.UserTriggerOrders = exports.UserOpenLimitOrders = void 0;
4
4
  const convert_1 = require("./convert");
5
- class UserOpenOrders {
5
+ class UserOpenLimitOrders {
6
6
  orders;
7
7
  constructor() {
8
8
  this.orders = new Map();
9
9
  }
10
- get(market) {
10
+ get(market, orderbookId) {
11
+ return this.orders.get(market)?.get(orderbookId);
12
+ }
13
+ getByMarket(market) {
11
14
  return this.orders.get(market);
12
15
  }
13
16
  insert(order) {
14
- const current = this.orders.get(order.marketPubkey) ?? [];
17
+ let marketMap = this.orders.get(order.marketPubkey);
18
+ if (!marketMap) {
19
+ marketMap = new Map();
20
+ this.orders.set(order.marketPubkey, marketMap);
21
+ }
22
+ const current = marketMap.get(order.orderbookId) ?? [];
15
23
  current.push(order);
16
- this.orders.set(order.marketPubkey, current);
24
+ marketMap.set(order.orderbookId, current);
17
25
  }
18
26
  upsert(update) {
19
27
  const order = (0, convert_1.orderFromUpdate)(update);
20
- const current = this.orders.get(order.marketPubkey) ?? [];
28
+ let marketMap = this.orders.get(order.marketPubkey);
29
+ if (!marketMap) {
30
+ marketMap = new Map();
31
+ this.orders.set(order.marketPubkey, marketMap);
32
+ }
33
+ const current = marketMap.get(order.orderbookId) ?? [];
21
34
  const next = current.filter((existing) => existing.orderHash !== order.orderHash);
22
35
  next.push(order);
23
- this.orders.set(order.marketPubkey, next);
36
+ marketMap.set(order.orderbookId, next);
24
37
  }
25
38
  remove(orderHash) {
26
- for (const [market, orders] of this.orders.entries()) {
27
- this.orders.set(market, orders.filter((order) => order.orderHash !== orderHash));
39
+ for (const [, marketMap] of this.orders.entries()) {
40
+ for (const [orderbookId, orderList] of marketMap.entries()) {
41
+ marketMap.set(orderbookId, orderList.filter((order) => order.orderHash !== orderHash));
42
+ }
28
43
  }
29
44
  }
30
45
  clear() {
31
46
  this.orders.clear();
32
47
  }
33
48
  isEmpty() {
34
- return Array.from(this.orders.values()).every((orders) => orders.length === 0);
49
+ for (const marketMap of this.orders.values()) {
50
+ for (const orderList of marketMap.values()) {
51
+ if (orderList.length > 0) {
52
+ return false;
53
+ }
54
+ }
55
+ }
56
+ return true;
35
57
  }
36
58
  }
37
- exports.UserOpenOrders = UserOpenOrders;
59
+ exports.UserOpenLimitOrders = UserOpenLimitOrders;
38
60
  class UserTriggerOrders {
39
61
  orders;
40
62
  constructor() {
41
63
  this.orders = new Map();
42
64
  }
43
- get(orderbookId) {
44
- return this.orders.get(orderbookId);
65
+ get(market, orderbookId) {
66
+ return this.orders.get(market)?.get(orderbookId);
67
+ }
68
+ getByMarket(market) {
69
+ return this.orders.get(market);
45
70
  }
46
71
  getById(triggerOrderId) {
47
- for (const orders of this.orders.values()) {
48
- const found = orders.find((order) => order.triggerOrderId === triggerOrderId);
49
- if (found) {
50
- return found;
72
+ for (const marketMap of this.orders.values()) {
73
+ for (const orderList of marketMap.values()) {
74
+ const found = orderList.find((order) => order.triggerOrderId === triggerOrderId);
75
+ if (found) {
76
+ return found;
77
+ }
51
78
  }
52
79
  }
53
80
  return undefined;
54
81
  }
55
82
  insert(order) {
56
- const current = this.orders.get(order.orderbookId) ?? [];
83
+ let marketMap = this.orders.get(order.marketPubkey);
84
+ if (!marketMap) {
85
+ marketMap = new Map();
86
+ this.orders.set(order.marketPubkey, marketMap);
87
+ }
88
+ const current = marketMap.get(order.orderbookId) ?? [];
57
89
  current.push(order);
58
- this.orders.set(order.orderbookId, current);
90
+ marketMap.set(order.orderbookId, current);
59
91
  }
60
92
  remove(triggerOrderId) {
61
- for (const [orderbookId, orders] of this.orders.entries()) {
62
- const index = orders.findIndex((order) => order.triggerOrderId === triggerOrderId);
63
- if (index >= 0) {
64
- const [removed] = orders.splice(index, 1);
65
- this.orders.set(orderbookId, orders);
66
- return removed;
93
+ for (const [, marketMap] of this.orders.entries()) {
94
+ for (const [orderbookId, orderList] of marketMap.entries()) {
95
+ const index = orderList.findIndex((order) => order.triggerOrderId === triggerOrderId);
96
+ if (index >= 0) {
97
+ const [removed] = orderList.splice(index, 1);
98
+ marketMap.set(orderbookId, orderList);
99
+ return removed;
100
+ }
67
101
  }
68
102
  }
69
103
  return undefined;
@@ -72,13 +106,32 @@ class UserTriggerOrders {
72
106
  this.orders.clear();
73
107
  }
74
108
  isEmpty() {
75
- return Array.from(this.orders.values()).every((orders) => orders.length === 0);
109
+ for (const marketMap of this.orders.values()) {
110
+ for (const orderList of marketMap.values()) {
111
+ if (orderList.length > 0) {
112
+ return false;
113
+ }
114
+ }
115
+ }
116
+ return true;
76
117
  }
77
118
  len() {
78
- return Array.from(this.orders.values()).reduce((acc, orders) => acc + orders.length, 0);
119
+ let count = 0;
120
+ for (const marketMap of this.orders.values()) {
121
+ for (const orderList of marketMap.values()) {
122
+ count += orderList.length;
123
+ }
124
+ }
125
+ return count;
79
126
  }
80
127
  all() {
81
- return Array.from(this.orders.values()).flatMap((orders) => orders);
128
+ const result = [];
129
+ for (const marketMap of this.orders.values()) {
130
+ for (const orderList of marketMap.values()) {
131
+ result.push(...orderList);
132
+ }
133
+ }
134
+ return result;
82
135
  }
83
136
  }
84
137
  exports.UserTriggerOrders = UserTriggerOrders;
@@ -1 +1 @@
1
- {"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/domain/order/state.ts"],"names":[],"mappings":"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","sourcesContent":["import type { OrderBookId, PubkeyStr } from \"../../shared\";\nimport type { Order, TriggerOrder } from \"./index\";\nimport type { OrderUpdate } from \"./wire\";\nimport { orderFromUpdate } from \"./convert\";\n\nexport class UserOpenOrders {\n readonly orders: Map<PubkeyStr, Order[]>;\n\n constructor() {\n this.orders = new Map();\n }\n\n get(market: PubkeyStr): Order[] | undefined {\n return this.orders.get(market);\n }\n\n insert(order: Order): void {\n const current = this.orders.get(order.marketPubkey) ?? [];\n current.push(order);\n this.orders.set(order.marketPubkey, current);\n }\n\n upsert(update: OrderUpdate): void {\n const order = orderFromUpdate(update);\n const current = this.orders.get(order.marketPubkey) ?? [];\n const next = current.filter((existing) => existing.orderHash !== order.orderHash);\n next.push(order);\n this.orders.set(order.marketPubkey, next);\n }\n\n remove(orderHash: string): void {\n for (const [market, orders] of this.orders.entries()) {\n this.orders.set(\n market,\n orders.filter((order) => order.orderHash !== orderHash)\n );\n }\n }\n\n clear(): void {\n this.orders.clear();\n }\n\n isEmpty(): boolean {\n return Array.from(this.orders.values()).every((orders) => orders.length === 0);\n }\n}\n\nexport class UserTriggerOrders {\n readonly orders: Map<OrderBookId, TriggerOrder[]>;\n\n constructor() {\n this.orders = new Map();\n }\n\n get(orderbookId: OrderBookId): TriggerOrder[] | undefined {\n return this.orders.get(orderbookId);\n }\n\n getById(triggerOrderId: string): TriggerOrder | undefined {\n for (const orders of this.orders.values()) {\n const found = orders.find((order) => order.triggerOrderId === triggerOrderId);\n if (found) {\n return found;\n }\n }\n\n return undefined;\n }\n\n insert(order: TriggerOrder): void {\n const current = this.orders.get(order.orderbookId) ?? [];\n current.push(order);\n this.orders.set(order.orderbookId, current);\n }\n\n remove(triggerOrderId: string): TriggerOrder | undefined {\n for (const [orderbookId, orders] of this.orders.entries()) {\n const index = orders.findIndex((order) => order.triggerOrderId === triggerOrderId);\n if (index >= 0) {\n const [removed] = orders.splice(index, 1);\n this.orders.set(orderbookId, orders);\n return removed;\n }\n }\n\n return undefined;\n }\n\n clear(): void {\n this.orders.clear();\n }\n\n isEmpty(): boolean {\n return Array.from(this.orders.values()).every((orders) => orders.length === 0);\n }\n\n len(): number {\n return Array.from(this.orders.values()).reduce((acc, orders) => acc + orders.length, 0);\n }\n\n all(): TriggerOrder[] {\n return Array.from(this.orders.values()).flatMap((orders) => orders);\n }\n}\n"]}
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/domain/order/state.ts"],"names":[],"mappings":"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","sourcesContent":["import type { OrderBookId, PubkeyStr } from \"../../shared\";\nimport type { LimitOrder, TriggerOrder } from \"./index\";\nimport type { OrderUpdate } from \"./wire\";\nimport { orderFromUpdate } from \"./convert\";\n\nexport class UserOpenLimitOrders {\n readonly orders: Map<PubkeyStr, Map<OrderBookId, LimitOrder[]>>;\n\n constructor() {\n this.orders = new Map();\n }\n\n get(market: PubkeyStr, orderbookId: OrderBookId): LimitOrder[] | undefined {\n return this.orders.get(market)?.get(orderbookId);\n }\n\n getByMarket(market: PubkeyStr): Map<OrderBookId, LimitOrder[]> | undefined {\n return this.orders.get(market);\n }\n\n insert(order: LimitOrder): void {\n let marketMap = this.orders.get(order.marketPubkey);\n if (!marketMap) {\n marketMap = new Map();\n this.orders.set(order.marketPubkey, marketMap);\n }\n const current = marketMap.get(order.orderbookId) ?? [];\n current.push(order);\n marketMap.set(order.orderbookId, current);\n }\n\n upsert(update: OrderUpdate): void {\n const order = orderFromUpdate(update);\n let marketMap = this.orders.get(order.marketPubkey);\n if (!marketMap) {\n marketMap = new Map();\n this.orders.set(order.marketPubkey, marketMap);\n }\n const current = marketMap.get(order.orderbookId) ?? [];\n const next = current.filter((existing) => existing.orderHash !== order.orderHash);\n next.push(order);\n marketMap.set(order.orderbookId, next);\n }\n\n remove(orderHash: string): void {\n for (const [, marketMap] of this.orders.entries()) {\n for (const [orderbookId, orderList] of marketMap.entries()) {\n marketMap.set(\n orderbookId,\n orderList.filter((order) => order.orderHash !== orderHash)\n );\n }\n }\n }\n\n clear(): void {\n this.orders.clear();\n }\n\n isEmpty(): boolean {\n for (const marketMap of this.orders.values()) {\n for (const orderList of marketMap.values()) {\n if (orderList.length > 0) {\n return false;\n }\n }\n }\n return true;\n }\n}\n\nexport class UserTriggerOrders {\n readonly orders: Map<PubkeyStr, Map<OrderBookId, TriggerOrder[]>>;\n\n constructor() {\n this.orders = new Map();\n }\n\n get(market: PubkeyStr, orderbookId: OrderBookId): TriggerOrder[] | undefined {\n return this.orders.get(market)?.get(orderbookId);\n }\n\n getByMarket(market: PubkeyStr): Map<OrderBookId, TriggerOrder[]> | undefined {\n return this.orders.get(market);\n }\n\n getById(triggerOrderId: string): TriggerOrder | undefined {\n for (const marketMap of this.orders.values()) {\n for (const orderList of marketMap.values()) {\n const found = orderList.find((order) => order.triggerOrderId === triggerOrderId);\n if (found) {\n return found;\n }\n }\n }\n\n return undefined;\n }\n\n insert(order: TriggerOrder): void {\n let marketMap = this.orders.get(order.marketPubkey);\n if (!marketMap) {\n marketMap = new Map();\n this.orders.set(order.marketPubkey, marketMap);\n }\n const current = marketMap.get(order.orderbookId) ?? [];\n current.push(order);\n marketMap.set(order.orderbookId, current);\n }\n\n remove(triggerOrderId: string): TriggerOrder | undefined {\n for (const [, marketMap] of this.orders.entries()) {\n for (const [orderbookId, orderList] of marketMap.entries()) {\n const index = orderList.findIndex((order) => order.triggerOrderId === triggerOrderId);\n if (index >= 0) {\n const [removed] = orderList.splice(index, 1);\n marketMap.set(orderbookId, orderList);\n return removed;\n }\n }\n }\n\n return undefined;\n }\n\n clear(): void {\n this.orders.clear();\n }\n\n isEmpty(): boolean {\n for (const marketMap of this.orders.values()) {\n for (const orderList of marketMap.values()) {\n if (orderList.length > 0) {\n return false;\n }\n }\n }\n return true;\n }\n\n len(): number {\n let count = 0;\n for (const marketMap of this.orders.values()) {\n for (const orderList of marketMap.values()) {\n count += orderList.length;\n }\n }\n return count;\n }\n\n all(): TriggerOrder[] {\n const result: TriggerOrder[] = [];\n for (const marketMap of this.orders.values()) {\n for (const orderList of marketMap.values()) {\n result.push(...orderList);\n }\n }\n return result;\n }\n}\n"]}
@@ -1,12 +1,16 @@
1
- import type { PublicKey } from "@solana/web3.js";
1
+ import { Transaction, type PublicKey, type TransactionInstruction } from "@solana/web3.js";
2
2
  import type { ClientContext } from "../../context";
3
- import type { Orderbook as ProgramOrderbook } from "../../program/types";
3
+ import type { CloseOrderbookAltParams, CloseOrderbookParams, Orderbook as ProgramOrderbook } from "../../program/types";
4
4
  import type { OrderbookDepthResponse } from "./wire";
5
5
  export declare class Orderbooks {
6
6
  private readonly client;
7
7
  constructor(client: ClientContext);
8
8
  pda(mintA: PublicKey, mintB: PublicKey): PublicKey;
9
9
  get(orderbookId: string, depth?: number): Promise<OrderbookDepthResponse>;
10
+ closeOrderbookAltIx(params: CloseOrderbookAltParams): TransactionInstruction;
11
+ closeOrderbookIx(params: CloseOrderbookParams): TransactionInstruction;
12
+ closeOrderbookAltTx(params: CloseOrderbookAltParams): Transaction;
13
+ closeOrderbookTx(params: CloseOrderbookParams): Transaction;
10
14
  getOnchain(mintA: PublicKey, mintB: PublicKey): Promise<ProgramOrderbook>;
11
15
  }
12
16
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/domain/orderbook/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAMnD,OAAO,KAAK,EAAE,SAAS,IAAI,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAC;AAErD,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,aAAa;IAIlD,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,GAAG,SAAS;IAM5C,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAQzE,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAWhF"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/domain/orderbook/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAC3F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAUnD,OAAO,KAAK,EACV,uBAAuB,EACvB,oBAAoB,EACpB,SAAS,IAAI,gBAAgB,EAC9B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAC;AAErD,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,aAAa;IAIlD,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,GAAG,SAAS;IAM5C,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAQ/E,mBAAmB,CAAC,MAAM,EAAE,uBAAuB,GAAG,sBAAsB;IAI5E,gBAAgB,CAAC,MAAM,EAAE,oBAAoB,GAAG,sBAAsB;IAItE,mBAAmB,CAAC,MAAM,EAAE,uBAAuB,GAAG,WAAW;IAKjE,gBAAgB,CAAC,MAAM,EAAE,oBAAoB,GAAG,WAAW;IAOrD,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAWhF"}
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Orderbooks = void 0;
4
+ const web3_js_1 = require("@solana/web3.js");
4
5
  const context_1 = require("../../context");
5
6
  const error_1 = require("../../program/error");
6
7
  const http_1 = require("../../http");
8
+ const instructions_1 = require("../../program/instructions");
7
9
  const pda_1 = require("../../program/pda");
8
10
  const accounts_1 = require("../../program/accounts");
9
11
  class Orderbooks {
@@ -21,6 +23,21 @@ class Orderbooks {
21
23
  const url = `${this.client.http.baseUrl()}/api/orderbook/${encodeURIComponent(orderbookId)}${query}`;
22
24
  return this.client.http.get(url, http_1.RetryPolicy.Idempotent);
23
25
  }
26
+ // ── On-chain transaction builders ────────────────────────────────────
27
+ closeOrderbookAltIx(params) {
28
+ return (0, instructions_1.buildCloseOrderbookAltIx)(params, this.client.programId);
29
+ }
30
+ closeOrderbookIx(params) {
31
+ return (0, instructions_1.buildCloseOrderbookIx)(params, this.client.programId);
32
+ }
33
+ closeOrderbookAltTx(params) {
34
+ const ix = this.closeOrderbookAltIx(params);
35
+ return new web3_js_1.Transaction({ feePayer: params.operator }).add(ix);
36
+ }
37
+ closeOrderbookTx(params) {
38
+ const ix = this.closeOrderbookIx(params);
39
+ return new web3_js_1.Transaction({ feePayer: params.operator }).add(ix);
40
+ }
24
41
  // ── On-chain account fetchers (require Connection) ──────────────────
25
42
  async getOnchain(mintA, mintB) {
26
43
  const connection = (0, context_1.requireConnection)(this.client);
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/domain/orderbook/client.ts"],"names":[],"mappings":";;;AAEA,2CAAkD;AAClD,+CAAsD;AACtD,qCAAyC;AACzC,2CAAoD;AACpD,qDAA6F;AAI7F,MAAa,UAAU;IACQ;IAA7B,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAEtD,wEAAwE;IAExE,GAAG,CAAC,KAAgB,EAAE,KAAgB;QACpC,OAAO,IAAA,qBAAe,EAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IACjE,CAAC;IAED,wEAAwE;IAExE,KAAK,CAAC,GAAG,CAAC,WAAmB,EAAE,KAAc;QAC3C,MAAM,KAAK,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,kBAAkB,CAAC,WAAW,CAAC,GAAG,KAAK,EAAE,CAAC;QACrG,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAyB,GAAG,EAAE,kBAAW,CAAC,UAAU,CAAC,CAAC;IACnF,CAAC;IAED,uEAAuE;IAEvE,KAAK,CAAC,UAAU,CAAC,KAAgB,EAAE,KAAgB;QACjD,MAAM,UAAU,GAAG,IAAA,2BAAiB,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClD,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC5C,MAAM,WAAW,GAAG,MAAM,UAAU,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;QAClE,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,uBAAe,CAAC,eAAe,CACnC,iBAAiB,KAAK,CAAC,QAAQ,EAAE,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,CAC1D,CAAC;QACJ,CAAC;QACD,OAAO,IAAA,+BAA2B,EAAC,WAAW,CAAC,IAAc,CAAC,CAAC;IACjE,CAAC;CACF;AA9BD,gCA8BC","sourcesContent":["import type { PublicKey } from \"@solana/web3.js\";\nimport type { ClientContext } from \"../../context\";\nimport { requireConnection } from \"../../context\";\nimport { ProgramSdkError } from \"../../program/error\";\nimport { RetryPolicy } from \"../../http\";\nimport { getOrderbookPda } from \"../../program/pda\";\nimport { deserializeOrderbook as deserializeProgramOrderbook } from \"../../program/accounts\";\nimport type { Orderbook as ProgramOrderbook } from \"../../program/types\";\nimport type { OrderbookDepthResponse } from \"./wire\";\n\nexport class Orderbooks {\n constructor(private readonly client: ClientContext) {}\n\n // ── PDA helpers ──────────────────────────────────────────────────────\n\n pda(mintA: PublicKey, mintB: PublicKey): PublicKey {\n return getOrderbookPda(mintA, mintB, this.client.programId)[0];\n }\n\n // ── HTTP methods ─────────────────────────────────────────────────────\n\n async get(orderbookId: string, depth?: number): Promise<OrderbookDepthResponse> {\n const query = depth !== undefined ? `?depth=${depth}` : \"\";\n const url = `${this.client.http.baseUrl()}/api/orderbook/${encodeURIComponent(orderbookId)}${query}`;\n return this.client.http.get<OrderbookDepthResponse>(url, RetryPolicy.Idempotent);\n }\n\n // ── On-chain account fetchers (require Connection) ──────────────────\n\n async getOnchain(mintA: PublicKey, mintB: PublicKey): Promise<ProgramOrderbook> {\n const connection = requireConnection(this.client);\n const orderbookPda = this.pda(mintA, mintB);\n const accountInfo = await connection.getAccountInfo(orderbookPda);\n if (!accountInfo) {\n throw ProgramSdkError.accountNotFound(\n `Orderbook for ${mintA.toBase58()} / ${mintB.toBase58()}`\n );\n }\n return deserializeProgramOrderbook(accountInfo.data as Buffer);\n }\n}\n"]}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/domain/orderbook/client.ts"],"names":[],"mappings":";;;AAAA,6CAA2F;AAE3F,2CAAkD;AAClD,+CAAsD;AACtD,qCAAyC;AACzC,6DAGoC;AACpC,2CAAoD;AACpD,qDAA6F;AAQ7F,MAAa,UAAU;IACQ;IAA7B,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAEtD,wEAAwE;IAExE,GAAG,CAAC,KAAgB,EAAE,KAAgB;QACpC,OAAO,IAAA,qBAAe,EAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IACjE,CAAC;IAED,wEAAwE;IAExE,KAAK,CAAC,GAAG,CAAC,WAAmB,EAAE,KAAc;QAC3C,MAAM,KAAK,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,kBAAkB,CAAC,WAAW,CAAC,GAAG,KAAK,EAAE,CAAC;QACrG,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAyB,GAAG,EAAE,kBAAW,CAAC,UAAU,CAAC,CAAC;IACnF,CAAC;IAED,wEAAwE;IAExE,mBAAmB,CAAC,MAA+B;QACjD,OAAO,IAAA,uCAAwB,EAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACjE,CAAC;IAED,gBAAgB,CAAC,MAA4B;QAC3C,OAAO,IAAA,oCAAqB,EAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC9D,CAAC;IAED,mBAAmB,CAAC,MAA+B;QACjD,MAAM,EAAE,GAAG,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAC5C,OAAO,IAAI,qBAAW,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,gBAAgB,CAAC,MAA4B;QAC3C,MAAM,EAAE,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QACzC,OAAO,IAAI,qBAAW,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChE,CAAC;IAED,uEAAuE;IAEvE,KAAK,CAAC,UAAU,CAAC,KAAgB,EAAE,KAAgB;QACjD,MAAM,UAAU,GAAG,IAAA,2BAAiB,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClD,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC5C,MAAM,WAAW,GAAG,MAAM,UAAU,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;QAClE,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,uBAAe,CAAC,eAAe,CACnC,iBAAiB,KAAK,CAAC,QAAQ,EAAE,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,CAC1D,CAAC;QACJ,CAAC;QACD,OAAO,IAAA,+BAA2B,EAAC,WAAW,CAAC,IAAc,CAAC,CAAC;IACjE,CAAC;CACF;AAlDD,gCAkDC","sourcesContent":["import { Transaction, type PublicKey, type TransactionInstruction } from \"@solana/web3.js\";\nimport type { ClientContext } from \"../../context\";\nimport { requireConnection } from \"../../context\";\nimport { ProgramSdkError } from \"../../program/error\";\nimport { RetryPolicy } from \"../../http\";\nimport {\n buildCloseOrderbookAltIx,\n buildCloseOrderbookIx,\n} from \"../../program/instructions\";\nimport { getOrderbookPda } from \"../../program/pda\";\nimport { deserializeOrderbook as deserializeProgramOrderbook } from \"../../program/accounts\";\nimport type {\n CloseOrderbookAltParams,\n CloseOrderbookParams,\n Orderbook as ProgramOrderbook,\n} from \"../../program/types\";\nimport type { OrderbookDepthResponse } from \"./wire\";\n\nexport class Orderbooks {\n constructor(private readonly client: ClientContext) {}\n\n // ── PDA helpers ──────────────────────────────────────────────────────\n\n pda(mintA: PublicKey, mintB: PublicKey): PublicKey {\n return getOrderbookPda(mintA, mintB, this.client.programId)[0];\n }\n\n // ── HTTP methods ─────────────────────────────────────────────────────\n\n async get(orderbookId: string, depth?: number): Promise<OrderbookDepthResponse> {\n const query = depth !== undefined ? `?depth=${depth}` : \"\";\n const url = `${this.client.http.baseUrl()}/api/orderbook/${encodeURIComponent(orderbookId)}${query}`;\n return this.client.http.get<OrderbookDepthResponse>(url, RetryPolicy.Idempotent);\n }\n\n // ── On-chain transaction builders ────────────────────────────────────\n\n closeOrderbookAltIx(params: CloseOrderbookAltParams): TransactionInstruction {\n return buildCloseOrderbookAltIx(params, this.client.programId);\n }\n\n closeOrderbookIx(params: CloseOrderbookParams): TransactionInstruction {\n return buildCloseOrderbookIx(params, this.client.programId);\n }\n\n closeOrderbookAltTx(params: CloseOrderbookAltParams): Transaction {\n const ix = this.closeOrderbookAltIx(params);\n return new Transaction({ feePayer: params.operator }).add(ix);\n }\n\n closeOrderbookTx(params: CloseOrderbookParams): Transaction {\n const ix = this.closeOrderbookIx(params);\n return new Transaction({ feePayer: params.operator }).add(ix);\n }\n\n // ── On-chain account fetchers (require Connection) ──────────────────\n\n async getOnchain(mintA: PublicKey, mintB: PublicKey): Promise<ProgramOrderbook> {\n const connection = requireConnection(this.client);\n const orderbookPda = this.pda(mintA, mintB);\n const accountInfo = await connection.getAccountInfo(orderbookPda);\n if (!accountInfo) {\n throw ProgramSdkError.accountNotFound(\n `Orderbook for ${mintA.toBase58()} / ${mintB.toBase58()}`\n );\n }\n return deserializeProgramOrderbook(accountInfo.data as Buffer);\n }\n}\n"]}
@@ -28,7 +28,7 @@ export interface OutcomeImpact {
28
28
  dollar: string;
29
29
  isPositive: boolean;
30
30
  }
31
- export declare function impactPct(pair: OrderBookPair, depositPrice: Decimal): [number, string];
31
+ export declare function impactPct(depositPrice: Decimal, conditionalPrice: Decimal): [number, string];
32
32
  export declare function impact(depositAssetPrice: Decimal, conditionalPrice: Decimal): OutcomeImpact;
33
33
  /**
34
34
  * Derive scaling decimals from an orderbook pair's token metadata.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/domain/orderbook/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,YAAY,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAElD,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAElD,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,SAAS,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,gBAAgB,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,IAAI,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,OAAO,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAQtF;AAED,wBAAgB,MAAM,CACpB,iBAAiB,EAAE,OAAO,EAC1B,gBAAgB,EAAE,OAAO,GACxB,aAAa,CAef;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,iBAAiB,CAUxE;AAED,0CAA0C;AAC1C,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,CAE9D;AAED,+DAA+D;AAC/D,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,CAEhE;AAED,gEAAgE;AAChE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,CAEjE;AAED,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;gBAEf,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE;CAMnD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/domain/orderbook/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,YAAY,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAElD,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAElD,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,SAAS,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,gBAAgB,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,IAAI,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,SAAS,CAAC,YAAY,EAAE,OAAO,EAAE,gBAAgB,EAAE,OAAO,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAO5F;AAED,wBAAgB,MAAM,CACpB,iBAAiB,EAAE,OAAO,EAC1B,gBAAgB,EAAE,OAAO,GACxB,aAAa,CAef;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,iBAAiB,CAUxE;AAED,0CAA0C;AAC1C,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,CAE9D;AAED,+DAA+D;AAC/D,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,CAEhE;AAED,gEAAgE;AAChE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,CAEjE;AAED,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;gBAEf,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE;CAMnD"}
@@ -13,9 +13,6 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
13
13
  var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
- var __importDefault = (this && this.__importDefault) || function (mod) {
17
- return (mod && mod.__esModule) ? mod : { "default": mod };
18
- };
19
16
  Object.defineProperty(exports, "__esModule", { value: true });
20
17
  exports.OrderBookValidationError = exports.orderBookPairFromWire = void 0;
21
18
  exports.impactPct = impactPct;
@@ -24,7 +21,6 @@ exports.orderbookDecimals = orderbookDecimals;
24
21
  exports.orderBookMarket = orderBookMarket;
25
22
  exports.orderBookBaseMint = orderBookBaseMint;
26
23
  exports.orderBookQuoteMint = orderBookQuoteMint;
27
- const decimal_js_1 = __importDefault(require("decimal.js"));
28
24
  const web3_js_1 = require("@solana/web3.js");
29
25
  __exportStar(require("./client"), exports);
30
26
  __exportStar(require("./wire"), exports);
@@ -32,12 +28,11 @@ __exportStar(require("./state"), exports);
32
28
  __exportStar(require("./ticker"), exports);
33
29
  var convert_1 = require("./convert");
34
30
  Object.defineProperty(exports, "orderBookPairFromWire", { enumerable: true, get: function () { return convert_1.orderBookPairFromWire; } });
35
- function impactPct(pair, depositPrice) {
36
- if (depositPrice.isZero() || !pair.lastTradePrice) {
31
+ function impactPct(depositPrice, conditionalPrice) {
32
+ if (depositPrice.isZero() || conditionalPrice.isZero()) {
37
33
  return [0, ""];
38
34
  }
39
- const conditional = new decimal_js_1.default(pair.lastTradePrice);
40
- const value = conditional.minus(depositPrice).div(depositPrice).mul(100);
35
+ const value = conditionalPrice.minus(depositPrice).div(depositPrice).mul(100);
41
36
  return [value.toNumber(), value.greaterThan(0) ? "+" : ""];
42
37
  }
43
38
  function impact(depositAssetPrice, conditionalPrice) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/domain/orderbook/index.ts"],"names":[],"mappings":"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","sourcesContent":["import Decimal from \"decimal.js\";\nimport { PublicKey } from \"@solana/web3.js\";\nimport type { OrderBookId, PubkeyStr } from \"../../shared\";\nimport type { OrderbookDecimals } from \"../../shared/scaling\";\nimport type { ConditionalToken } from \"../market\";\n\nexport * from \"./client\";\nexport * from \"./wire\";\nexport * from \"./state\";\nexport * from \"./ticker\";\nexport { orderBookPairFromWire } from \"./convert\";\n\nexport interface OrderBookPair {\n id: number;\n marketPubkey: PubkeyStr;\n orderbookId: OrderBookId;\n base: ConditionalToken;\n quote: ConditionalToken;\n outcomeIndex: number;\n tickSize: number;\n totalBids: number;\n totalAsks: number;\n lastTradePrice?: string;\n lastTradeTime?: Date;\n active: boolean;\n}\n\nexport interface OutcomeImpact {\n sign: string;\n pct: number;\n dollar: string;\n isPositive: boolean;\n}\n\nexport function impactPct(pair: OrderBookPair, depositPrice: Decimal): [number, string] {\n if (depositPrice.isZero() || !pair.lastTradePrice) {\n return [0, \"\"];\n }\n\n const conditional = new Decimal(pair.lastTradePrice);\n const value = conditional.minus(depositPrice).div(depositPrice).mul(100);\n return [value.toNumber(), value.greaterThan(0) ? \"+\" : \"\"];\n}\n\nexport function impact(\n depositAssetPrice: Decimal,\n conditionalPrice: Decimal\n): OutcomeImpact {\n if (depositAssetPrice.isZero()) {\n return { sign: \"\", pct: 0, dollar: \"0\", isPositive: false };\n }\n\n const pctDecimal = conditionalPrice.minus(depositAssetPrice).div(depositAssetPrice).mul(100);\n const pct = pctDecimal.toNumber();\n const dollar = conditionalPrice.minus(depositAssetPrice).abs().toString();\n\n return {\n sign: pct > 0 ? \"+\" : \"-\",\n pct: Math.abs(pct),\n dollar,\n isPositive: pct > 0,\n };\n}\n\n/**\n * Derive scaling decimals from an orderbook pair's token metadata.\n *\n * No REST call needed — decimals are computed from the base/quote token objects.\n */\nexport function orderbookDecimals(pair: OrderBookPair): OrderbookDecimals {\n const baseDecimals = pair.base.decimals;\n const quoteDecimals = pair.quote.decimals;\n return {\n orderbookId: pair.orderbookId,\n baseDecimals,\n quoteDecimals,\n priceDecimals: Math.max(0, 6 + quoteDecimals - baseDecimals),\n tickSize: BigInt(Math.max(pair.tickSize, 0)),\n };\n}\n\n/** Return the market as a `PublicKey`. */\nexport function orderBookMarket(pair: OrderBookPair): PublicKey {\n return new PublicKey(pair.marketPubkey);\n}\n\n/** Return the base conditional-token mint as a `PublicKey`. */\nexport function orderBookBaseMint(pair: OrderBookPair): PublicKey {\n return new PublicKey(pair.base.pubkey);\n}\n\n/** Return the quote conditional-token mint as a `PublicKey`. */\nexport function orderBookQuoteMint(pair: OrderBookPair): PublicKey {\n return new PublicKey(pair.quote.pubkey);\n}\n\nexport class OrderBookValidationError extends Error {\n readonly orderbookId: string;\n readonly details: string[];\n\n constructor(orderbookId: string, details: string[]) {\n super(`OrderBook validation errors (${orderbookId}): ${details.join(\"; \")}`);\n this.name = \"OrderBookValidationError\";\n this.orderbookId = orderbookId;\n this.details = details;\n }\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/domain/orderbook/index.ts"],"names":[],"mappings":"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","sourcesContent":["import Decimal from \"decimal.js\";\nimport { PublicKey } from \"@solana/web3.js\";\nimport type { OrderBookId, PubkeyStr } from \"../../shared\";\nimport type { OrderbookDecimals } from \"../../shared/scaling\";\nimport type { ConditionalToken } from \"../market\";\n\nexport * from \"./client\";\nexport * from \"./wire\";\nexport * from \"./state\";\nexport * from \"./ticker\";\nexport { orderBookPairFromWire } from \"./convert\";\n\nexport interface OrderBookPair {\n id: number;\n marketPubkey: PubkeyStr;\n orderbookId: OrderBookId;\n base: ConditionalToken;\n quote: ConditionalToken;\n outcomeIndex: number;\n tickSize: number;\n totalBids: number;\n totalAsks: number;\n lastTradePrice?: string;\n lastTradeTime?: Date;\n active: boolean;\n}\n\nexport interface OutcomeImpact {\n sign: string;\n pct: number;\n dollar: string;\n isPositive: boolean;\n}\n\nexport function impactPct(depositPrice: Decimal, conditionalPrice: Decimal): [number, string] {\n if (depositPrice.isZero() || conditionalPrice.isZero()) {\n return [0, \"\"];\n }\n\n const value = conditionalPrice.minus(depositPrice).div(depositPrice).mul(100);\n return [value.toNumber(), value.greaterThan(0) ? \"+\" : \"\"];\n}\n\nexport function impact(\n depositAssetPrice: Decimal,\n conditionalPrice: Decimal\n): OutcomeImpact {\n if (depositAssetPrice.isZero()) {\n return { sign: \"\", pct: 0, dollar: \"0\", isPositive: false };\n }\n\n const pctDecimal = conditionalPrice.minus(depositAssetPrice).div(depositAssetPrice).mul(100);\n const pct = pctDecimal.toNumber();\n const dollar = conditionalPrice.minus(depositAssetPrice).abs().toString();\n\n return {\n sign: pct > 0 ? \"+\" : \"-\",\n pct: Math.abs(pct),\n dollar,\n isPositive: pct > 0,\n };\n}\n\n/**\n * Derive scaling decimals from an orderbook pair's token metadata.\n *\n * No REST call needed — decimals are computed from the base/quote token objects.\n */\nexport function orderbookDecimals(pair: OrderBookPair): OrderbookDecimals {\n const baseDecimals = pair.base.decimals;\n const quoteDecimals = pair.quote.decimals;\n return {\n orderbookId: pair.orderbookId,\n baseDecimals,\n quoteDecimals,\n priceDecimals: Math.max(0, 6 + quoteDecimals - baseDecimals),\n tickSize: BigInt(Math.max(pair.tickSize, 0)),\n };\n}\n\n/** Return the market as a `PublicKey`. */\nexport function orderBookMarket(pair: OrderBookPair): PublicKey {\n return new PublicKey(pair.marketPubkey);\n}\n\n/** Return the base conditional-token mint as a `PublicKey`. */\nexport function orderBookBaseMint(pair: OrderBookPair): PublicKey {\n return new PublicKey(pair.base.pubkey);\n}\n\n/** Return the quote conditional-token mint as a `PublicKey`. */\nexport function orderBookQuoteMint(pair: OrderBookPair): PublicKey {\n return new PublicKey(pair.quote.pubkey);\n}\n\nexport class OrderBookValidationError extends Error {\n readonly orderbookId: string;\n readonly details: string[];\n\n constructor(orderbookId: string, details: string[]) {\n super(`OrderBook validation errors (${orderbookId}): ${details.join(\"; \")}`);\n this.name = \"OrderBookValidationError\";\n this.orderbookId = orderbookId;\n this.details = details;\n }\n}\n"]}
@@ -3,11 +3,33 @@ import type { OrderBook } from "./wire";
3
3
  export type OrderbookApplyResult = {
4
4
  kind: "applied";
5
5
  } | {
6
- kind: "stale";
6
+ kind: "ignored";
7
+ reason: OrderbookIgnoreReason;
7
8
  } | {
8
- kind: "gap_detected";
9
+ kind: "refresh_required";
10
+ reason: OrderbookRefreshReason;
11
+ };
12
+ export type OrderbookIgnoreReason = {
13
+ kind: "invalid_delta_sequence";
14
+ got: number;
15
+ } | {
16
+ kind: "stale_delta";
17
+ current: number;
18
+ got: number;
19
+ } | {
20
+ kind: "already_awaiting_snapshot";
21
+ got: number;
22
+ };
23
+ export type OrderbookRefreshReason = {
24
+ kind: "missing_snapshot";
25
+ got: number;
26
+ } | {
27
+ kind: "sequence_gap";
9
28
  expected: number;
10
29
  got: number;
30
+ } | {
31
+ kind: "server_resync";
32
+ got: number;
11
33
  };
12
34
  export declare class OrderbookState {
13
35
  readonly orderbookId: OrderBookId;
@@ -17,15 +39,16 @@ export declare class OrderbookState {
17
39
  private cachedBestBid;
18
40
  private cachedBestAsk;
19
41
  private hasSnapshot;
42
+ private awaitingSnapshot;
20
43
  constructor(orderbookId: OrderBookId);
21
44
  /**
22
45
  * Apply a WS orderbook message (snapshot replaces, delta merges).
23
46
  *
24
- * Snapshots are always applied. Deltas with a `seq` at or below the
25
- * current value are silently dropped to prevent stale updates. Deltas
26
- * that skip one or more expected sequence values are rejected so callers
27
- * can refresh from a fresh snapshot instead of mutating a corrupted book.
28
- * Server resync messages leave the book unchanged and return `stale`.
47
+ * Server resync messages take precedence and return `refresh_required`.
48
+ * Otherwise, snapshots are applied and deltas with a `seq` at or below the
49
+ * current value are ignored to prevent stale updates. Deltas that skip one
50
+ * or more expected sequence values are rejected so callers can refresh from
51
+ * a fresh snapshot instead of mutating a corrupted book.
29
52
  */
30
53
  apply(book: OrderBook): OrderbookApplyResult;
31
54
  bids(): ReadonlyMap<string, string>;
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/domain/orderbook/state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAExC,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5D,qBAAa,cAAc;IACzB,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,WAAW,CAAU;gBAEjB,WAAW,EAAE,WAAW;IAUpC;;;;;;;;OAQG;IACH,KAAK,CAAC,IAAI,EAAE,SAAS,GAAG,oBAAoB;IAuD5C,IAAI,IAAI,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;IAInC,IAAI,IAAI,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;IAInC,OAAO,IAAI,MAAM,GAAG,SAAS;IAe7B,OAAO,IAAI,MAAM,GAAG,SAAS;IAc7B,QAAQ,IAAI,MAAM,GAAG,SAAS;IAU9B,MAAM,IAAI,MAAM,GAAG,SAAS;IAU5B,OAAO,IAAI,OAAO;IAIlB,KAAK,IAAI,IAAI;CAQd"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../src/domain/orderbook/state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAExC,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,qBAAqB,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,CAAC;AAEjE,MAAM,MAAM,qBAAqB,GAC7B;IAAE,IAAI,EAAE,wBAAwB,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,2BAA2B,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvD,MAAM,MAAM,sBAAsB,GAC9B;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3C,qBAAa,cAAc;IACzB,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,WAAW,CAAU;IAC7B,OAAO,CAAC,gBAAgB,CAAU;gBAEtB,WAAW,EAAE,WAAW;IAWpC;;;;;;;;OAQG;IACH,KAAK,CAAC,IAAI,EAAE,SAAS,GAAG,oBAAoB;IAkF5C,IAAI,IAAI,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;IAInC,IAAI,IAAI,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC;IAInC,OAAO,IAAI,MAAM,GAAG,SAAS;IAe7B,OAAO,IAAI,MAAM,GAAG,SAAS;IAc7B,QAAQ,IAAI,MAAM,GAAG,SAAS;IAU9B,MAAM,IAAI,MAAM,GAAG,SAAS;IAU5B,OAAO,IAAI,OAAO;IAIlB,KAAK,IAAI,IAAI;CASd"}
@@ -13,6 +13,7 @@ class OrderbookState {
13
13
  cachedBestBid;
14
14
  cachedBestAsk;
15
15
  hasSnapshot;
16
+ awaitingSnapshot;
16
17
  constructor(orderbookId) {
17
18
  this.orderbookId = orderbookId;
18
19
  this.seq = 0;
@@ -21,40 +22,67 @@ class OrderbookState {
21
22
  this.cachedBestBid = null;
22
23
  this.cachedBestAsk = null;
23
24
  this.hasSnapshot = false;
25
+ this.awaitingSnapshot = false;
24
26
  }
25
27
  /**
26
28
  * Apply a WS orderbook message (snapshot replaces, delta merges).
27
29
  *
28
- * Snapshots are always applied. Deltas with a `seq` at or below the
29
- * current value are silently dropped to prevent stale updates. Deltas
30
- * that skip one or more expected sequence values are rejected so callers
31
- * can refresh from a fresh snapshot instead of mutating a corrupted book.
32
- * Server resync messages leave the book unchanged and return `stale`.
30
+ * Server resync messages take precedence and return `refresh_required`.
31
+ * Otherwise, snapshots are applied and deltas with a `seq` at or below the
32
+ * current value are ignored to prevent stale updates. Deltas that skip one
33
+ * or more expected sequence values are rejected so callers can refresh from
34
+ * a fresh snapshot instead of mutating a corrupted book.
33
35
  */
34
36
  apply(book) {
37
+ const seq = book.seq ?? 0;
35
38
  if (book.resync) {
36
- return { kind: "stale" };
39
+ this.awaitingSnapshot = true;
40
+ return {
41
+ kind: "refresh_required",
42
+ reason: { kind: "server_resync", got: seq },
43
+ };
37
44
  }
38
- const seq = book.seq ?? 0;
39
45
  if (book.is_snapshot) {
40
46
  this.bidsMap.clear();
41
47
  this.asksMap.clear();
42
48
  this.hasSnapshot = true;
49
+ this.awaitingSnapshot = false;
43
50
  }
44
51
  else {
52
+ if (this.awaitingSnapshot) {
53
+ return {
54
+ kind: "ignored",
55
+ reason: { kind: "already_awaiting_snapshot", got: seq },
56
+ };
57
+ }
45
58
  // The backend sends snapshots with seq=0 and starts delta seq at 1.
46
59
  // A delta with seq=0 means it has no valid sequence, so drop it.
47
60
  if (seq <= 0) {
48
- return { kind: "stale" };
61
+ return {
62
+ kind: "ignored",
63
+ reason: { kind: "invalid_delta_sequence", got: seq },
64
+ };
49
65
  }
50
66
  if (!this.hasSnapshot) {
51
- return { kind: "gap_detected", expected: 0, got: seq };
67
+ this.awaitingSnapshot = true;
68
+ return {
69
+ kind: "refresh_required",
70
+ reason: { kind: "missing_snapshot", got: seq },
71
+ };
52
72
  }
53
73
  if (seq <= this.seq) {
54
- return { kind: "stale" };
74
+ return {
75
+ kind: "ignored",
76
+ reason: { kind: "stale_delta", current: this.seq, got: seq },
77
+ };
55
78
  }
56
- if (seq !== this.seq + 1) {
57
- return { kind: "gap_detected", expected: this.seq + 1, got: seq };
79
+ const expected = this.seq + 1;
80
+ if (seq !== expected) {
81
+ this.awaitingSnapshot = true;
82
+ return {
83
+ kind: "refresh_required",
84
+ reason: { kind: "sequence_gap", expected, got: seq },
85
+ };
58
86
  }
59
87
  }
60
88
  this.seq = seq;
@@ -137,6 +165,7 @@ class OrderbookState {
137
165
  this.cachedBestBid = null;
138
166
  this.cachedBestAsk = null;
139
167
  this.hasSnapshot = false;
168
+ this.awaitingSnapshot = false;
140
169
  }
141
170
  }
142
171
  exports.OrderbookState = OrderbookState;
@@ -1 +1 @@
1
- {"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/domain/orderbook/state.ts"],"names":[],"mappings":";;;;;;AAAA,4DAAiC;AASjC,MAAa,cAAc;IAChB,WAAW,CAAc;IAClC,GAAG,CAAS;IACK,OAAO,CAAsB;IAC7B,OAAO,CAAsB;IACtC,aAAa,CAA4B;IACzC,aAAa,CAA4B;IACzC,WAAW,CAAU;IAE7B,YAAY,WAAwB;QAClC,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;QACb,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC;QACzB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;IAC3B,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,IAAe;QACnB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAC3B,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QAE1B,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACrB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACrB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,oEAAoE;YACpE,iEAAiE;YACjE,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;gBACb,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;YAC3B,CAAC;YAED,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBACtB,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;YACzD,CAAC;YAED,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;gBACpB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;YAC3B,CAAC;YAED,IAAI,GAAG,KAAK,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC;gBACzB,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;YACpE,CAAC;QACH,CAAC;QAED,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QAEf,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC9B,IAAI,IAAI,oBAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;gBACrC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACnC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC9B,IAAI,IAAI,oBAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;gBACrC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACnC,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;QAED,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAE1B,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC7B,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,OAAO;QACL,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;YAChC,OAAO,IAAI,CAAC,aAAa,CAAC;QAC5B,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;YAC/B,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;aAC3C,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,oBAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,oBAAO,CAAC,CAAC,CAAC,CAAC,CAAC;aAClD,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACV,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC;QAC5B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO;QACL,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;YAChC,OAAO,IAAI,CAAC,aAAa,CAAC;QAC5B,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;YAC/B,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;aAC3C,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,oBAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,oBAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACzD,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC;QAC5B,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,QAAQ;QACN,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC3B,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACjB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO,IAAI,oBAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACtD,CAAC;IAED,MAAM;QACJ,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC3B,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACjB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO,IAAI,oBAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;IAChD,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC;IAC5D,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;QACb,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;IAC3B,CAAC;CACF;AAxJD,wCAwJC","sourcesContent":["import Decimal from \"decimal.js\";\nimport type { OrderBookId } from \"../../shared\";\nimport type { OrderBook } from \"./wire\";\n\nexport type OrderbookApplyResult =\n | { kind: \"applied\" }\n | { kind: \"stale\" }\n | { kind: \"gap_detected\"; expected: number; got: number };\n\nexport class OrderbookState {\n readonly orderbookId: OrderBookId;\n seq: number;\n private readonly bidsMap: Map<string, string>;\n private readonly asksMap: Map<string, string>;\n private cachedBestBid: string | undefined | null;\n private cachedBestAsk: string | undefined | null;\n private hasSnapshot: boolean;\n\n constructor(orderbookId: OrderBookId) {\n this.orderbookId = orderbookId;\n this.seq = 0;\n this.bidsMap = new Map();\n this.asksMap = new Map();\n this.cachedBestBid = null;\n this.cachedBestAsk = null;\n this.hasSnapshot = false;\n }\n\n /**\n * Apply a WS orderbook message (snapshot replaces, delta merges).\n *\n * Snapshots are always applied. Deltas with a `seq` at or below the\n * current value are silently dropped to prevent stale updates. Deltas\n * that skip one or more expected sequence values are rejected so callers\n * can refresh from a fresh snapshot instead of mutating a corrupted book.\n * Server resync messages leave the book unchanged and return `stale`.\n */\n apply(book: OrderBook): OrderbookApplyResult {\n if (book.resync) {\n return { kind: \"stale\" };\n }\n\n const seq = book.seq ?? 0;\n\n if (book.is_snapshot) {\n this.bidsMap.clear();\n this.asksMap.clear();\n this.hasSnapshot = true;\n } else {\n // The backend sends snapshots with seq=0 and starts delta seq at 1.\n // A delta with seq=0 means it has no valid sequence, so drop it.\n if (seq <= 0) {\n return { kind: \"stale\" };\n }\n\n if (!this.hasSnapshot) {\n return { kind: \"gap_detected\", expected: 0, got: seq };\n }\n\n if (seq <= this.seq) {\n return { kind: \"stale\" };\n }\n\n if (seq !== this.seq + 1) {\n return { kind: \"gap_detected\", expected: this.seq + 1, got: seq };\n }\n }\n\n this.seq = seq;\n\n for (const level of book.bids) {\n if (new Decimal(level.size).isZero()) {\n this.bidsMap.delete(level.price);\n } else {\n this.bidsMap.set(level.price, level.size);\n }\n }\n\n for (const level of book.asks) {\n if (new Decimal(level.size).isZero()) {\n this.asksMap.delete(level.price);\n } else {\n this.asksMap.set(level.price, level.size);\n }\n }\n\n this.cachedBestBid = null;\n this.cachedBestAsk = null;\n\n return { kind: \"applied\" };\n }\n\n bids(): ReadonlyMap<string, string> {\n return this.bidsMap;\n }\n\n asks(): ReadonlyMap<string, string> {\n return this.asksMap;\n }\n\n bestBid(): string | undefined {\n if (this.cachedBestBid !== null) {\n return this.cachedBestBid;\n }\n if (this.bidsMap.size === 0) {\n this.cachedBestBid = undefined;\n return undefined;\n }\n const result = Array.from(this.bidsMap.keys())\n .sort((a, b) => new Decimal(a).cmp(new Decimal(b)))\n .at(-1);\n this.cachedBestBid = result;\n return result;\n }\n\n bestAsk(): string | undefined {\n if (this.cachedBestAsk !== null) {\n return this.cachedBestAsk;\n }\n if (this.asksMap.size === 0) {\n this.cachedBestAsk = undefined;\n return undefined;\n }\n const result = Array.from(this.asksMap.keys())\n .sort((a, b) => new Decimal(a).cmp(new Decimal(b)))[0];\n this.cachedBestAsk = result;\n return result;\n }\n\n midPrice(): string | undefined {\n const bid = this.bestBid();\n const ask = this.bestAsk();\n if (!bid || !ask) {\n return undefined;\n }\n\n return new Decimal(bid).plus(ask).div(2).toString();\n }\n\n spread(): string | undefined {\n const bid = this.bestBid();\n const ask = this.bestAsk();\n if (!bid || !ask) {\n return undefined;\n }\n\n return new Decimal(ask).minus(bid).toString();\n }\n\n isEmpty(): boolean {\n return this.bidsMap.size === 0 && this.asksMap.size === 0;\n }\n\n clear(): void {\n this.bidsMap.clear();\n this.asksMap.clear();\n this.seq = 0;\n this.cachedBestBid = null;\n this.cachedBestAsk = null;\n this.hasSnapshot = false;\n }\n}\n"]}
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/domain/orderbook/state.ts"],"names":[],"mappings":"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","sourcesContent":["import Decimal from \"decimal.js\";\nimport type { OrderBookId } from \"../../shared\";\nimport type { OrderBook } from \"./wire\";\n\nexport type OrderbookApplyResult =\n | { kind: \"applied\" }\n | { kind: \"ignored\"; reason: OrderbookIgnoreReason }\n | { kind: \"refresh_required\"; reason: OrderbookRefreshReason };\n\nexport type OrderbookIgnoreReason =\n | { kind: \"invalid_delta_sequence\"; got: number }\n | { kind: \"stale_delta\"; current: number; got: number }\n | { kind: \"already_awaiting_snapshot\"; got: number };\n\nexport type OrderbookRefreshReason =\n | { kind: \"missing_snapshot\"; got: number }\n | { kind: \"sequence_gap\"; expected: number; got: number }\n | { kind: \"server_resync\"; got: number };\n\nexport class OrderbookState {\n readonly orderbookId: OrderBookId;\n seq: number;\n private readonly bidsMap: Map<string, string>;\n private readonly asksMap: Map<string, string>;\n private cachedBestBid: string | undefined | null;\n private cachedBestAsk: string | undefined | null;\n private hasSnapshot: boolean;\n private awaitingSnapshot: boolean;\n\n constructor(orderbookId: OrderBookId) {\n this.orderbookId = orderbookId;\n this.seq = 0;\n this.bidsMap = new Map();\n this.asksMap = new Map();\n this.cachedBestBid = null;\n this.cachedBestAsk = null;\n this.hasSnapshot = false;\n this.awaitingSnapshot = false;\n }\n\n /**\n * Apply a WS orderbook message (snapshot replaces, delta merges).\n *\n * Server resync messages take precedence and return `refresh_required`.\n * Otherwise, snapshots are applied and deltas with a `seq` at or below the\n * current value are ignored to prevent stale updates. Deltas that skip one\n * or more expected sequence values are rejected so callers can refresh from\n * a fresh snapshot instead of mutating a corrupted book.\n */\n apply(book: OrderBook): OrderbookApplyResult {\n const seq = book.seq ?? 0;\n\n if (book.resync) {\n this.awaitingSnapshot = true;\n return {\n kind: \"refresh_required\",\n reason: { kind: \"server_resync\", got: seq },\n };\n }\n\n if (book.is_snapshot) {\n this.bidsMap.clear();\n this.asksMap.clear();\n this.hasSnapshot = true;\n this.awaitingSnapshot = false;\n } else {\n if (this.awaitingSnapshot) {\n return {\n kind: \"ignored\",\n reason: { kind: \"already_awaiting_snapshot\", got: seq },\n };\n }\n\n // The backend sends snapshots with seq=0 and starts delta seq at 1.\n // A delta with seq=0 means it has no valid sequence, so drop it.\n if (seq <= 0) {\n return {\n kind: \"ignored\",\n reason: { kind: \"invalid_delta_sequence\", got: seq },\n };\n }\n\n if (!this.hasSnapshot) {\n this.awaitingSnapshot = true;\n return {\n kind: \"refresh_required\",\n reason: { kind: \"missing_snapshot\", got: seq },\n };\n }\n\n if (seq <= this.seq) {\n return {\n kind: \"ignored\",\n reason: { kind: \"stale_delta\", current: this.seq, got: seq },\n };\n }\n\n const expected = this.seq + 1;\n if (seq !== expected) {\n this.awaitingSnapshot = true;\n return {\n kind: \"refresh_required\",\n reason: { kind: \"sequence_gap\", expected, got: seq },\n };\n }\n }\n\n this.seq = seq;\n\n for (const level of book.bids) {\n if (new Decimal(level.size).isZero()) {\n this.bidsMap.delete(level.price);\n } else {\n this.bidsMap.set(level.price, level.size);\n }\n }\n\n for (const level of book.asks) {\n if (new Decimal(level.size).isZero()) {\n this.asksMap.delete(level.price);\n } else {\n this.asksMap.set(level.price, level.size);\n }\n }\n\n this.cachedBestBid = null;\n this.cachedBestAsk = null;\n\n return { kind: \"applied\" };\n }\n\n bids(): ReadonlyMap<string, string> {\n return this.bidsMap;\n }\n\n asks(): ReadonlyMap<string, string> {\n return this.asksMap;\n }\n\n bestBid(): string | undefined {\n if (this.cachedBestBid !== null) {\n return this.cachedBestBid;\n }\n if (this.bidsMap.size === 0) {\n this.cachedBestBid = undefined;\n return undefined;\n }\n const result = Array.from(this.bidsMap.keys())\n .sort((a, b) => new Decimal(a).cmp(new Decimal(b)))\n .at(-1);\n this.cachedBestBid = result;\n return result;\n }\n\n bestAsk(): string | undefined {\n if (this.cachedBestAsk !== null) {\n return this.cachedBestAsk;\n }\n if (this.asksMap.size === 0) {\n this.cachedBestAsk = undefined;\n return undefined;\n }\n const result = Array.from(this.asksMap.keys())\n .sort((a, b) => new Decimal(a).cmp(new Decimal(b)))[0];\n this.cachedBestAsk = result;\n return result;\n }\n\n midPrice(): string | undefined {\n const bid = this.bestBid();\n const ask = this.bestAsk();\n if (!bid || !ask) {\n return undefined;\n }\n\n return new Decimal(bid).plus(ask).div(2).toString();\n }\n\n spread(): string | undefined {\n const bid = this.bestBid();\n const ask = this.bestAsk();\n if (!bid || !ask) {\n return undefined;\n }\n\n return new Decimal(ask).minus(bid).toString();\n }\n\n isEmpty(): boolean {\n return this.bidsMap.size === 0 && this.asksMap.size === 0;\n }\n\n clear(): void {\n this.bidsMap.clear();\n this.asksMap.clear();\n this.seq = 0;\n this.cachedBestBid = null;\n this.cachedBestAsk = null;\n this.hasSnapshot = false;\n this.awaitingSnapshot = false;\n }\n}\n"]}