@acta-markets/ts-sdk 0.0.1-beta

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 (263) hide show
  1. package/README.md +308 -0
  2. package/dist/actaClient.d.ts +46 -0
  3. package/dist/actaClient.js +99 -0
  4. package/dist/chain/client.d.ts +65 -0
  5. package/dist/chain/client.js +82 -0
  6. package/dist/chain/fetch.d.ts +204 -0
  7. package/dist/chain/fetch.js +392 -0
  8. package/dist/chain/fetch.test.d.ts +1 -0
  9. package/dist/chain/fetch.test.js +158 -0
  10. package/dist/chain/flows/index.d.ts +1 -0
  11. package/dist/chain/flows/index.js +1 -0
  12. package/dist/chain/flows/openPosition.d.ts +48 -0
  13. package/dist/chain/flows/openPosition.js +78 -0
  14. package/dist/chain/flows/openPosition.test.d.ts +1 -0
  15. package/dist/chain/flows/openPosition.test.js +43 -0
  16. package/dist/chain/helpers.d.ts +16 -0
  17. package/dist/chain/helpers.js +60 -0
  18. package/dist/chain/index.d.ts +9 -0
  19. package/dist/chain/index.js +9 -0
  20. package/dist/chain/instructions.admin.d.ts +44 -0
  21. package/dist/chain/instructions.admin.js +113 -0
  22. package/dist/chain/instructions.d.ts +5 -0
  23. package/dist/chain/instructions.js +5 -0
  24. package/dist/chain/instructions.maker.d.ts +34 -0
  25. package/dist/chain/instructions.maker.js +86 -0
  26. package/dist/chain/instructions.market.d.ts +39 -0
  27. package/dist/chain/instructions.market.js +107 -0
  28. package/dist/chain/instructions.oracle.d.ts +38 -0
  29. package/dist/chain/instructions.oracle.js +63 -0
  30. package/dist/chain/instructions.position.d.ts +82 -0
  31. package/dist/chain/instructions.position.js +240 -0
  32. package/dist/chain/instructions.resolve.test.d.ts +1 -0
  33. package/dist/chain/instructions.resolve.test.js +32 -0
  34. package/dist/chain/instructions.shared.d.ts +23 -0
  35. package/dist/chain/instructions.shared.js +55 -0
  36. package/dist/chain/orders.d.ts +40 -0
  37. package/dist/chain/orders.js +117 -0
  38. package/dist/chain/orders.test.d.ts +1 -0
  39. package/dist/chain/orders.test.js +67 -0
  40. package/dist/chain/signers.d.ts +9 -0
  41. package/dist/chain/signers.js +19 -0
  42. package/dist/chain/signers.test.d.ts +1 -0
  43. package/dist/chain/signers.test.js +13 -0
  44. package/dist/chain/token.d.ts +59 -0
  45. package/dist/chain/token.js +136 -0
  46. package/dist/chain/token.test.d.ts +1 -0
  47. package/dist/chain/token.test.js +69 -0
  48. package/dist/chain/tx.d.ts +72 -0
  49. package/dist/chain/tx.js +97 -0
  50. package/dist/cjs/actaClient.js +103 -0
  51. package/dist/cjs/chain/client.js +119 -0
  52. package/dist/cjs/chain/fetch.js +431 -0
  53. package/dist/cjs/chain/fetch.test.js +160 -0
  54. package/dist/cjs/chain/flows/index.js +17 -0
  55. package/dist/cjs/chain/flows/openPosition.js +81 -0
  56. package/dist/cjs/chain/flows/openPosition.test.js +45 -0
  57. package/dist/cjs/chain/helpers.js +67 -0
  58. package/dist/cjs/chain/index.js +48 -0
  59. package/dist/cjs/chain/instructions.admin.js +119 -0
  60. package/dist/cjs/chain/instructions.js +21 -0
  61. package/dist/cjs/chain/instructions.maker.js +92 -0
  62. package/dist/cjs/chain/instructions.market.js +112 -0
  63. package/dist/cjs/chain/instructions.oracle.js +70 -0
  64. package/dist/cjs/chain/instructions.position.js +247 -0
  65. package/dist/cjs/chain/instructions.resolve.test.js +34 -0
  66. package/dist/cjs/chain/instructions.shared.js +64 -0
  67. package/dist/cjs/chain/orders.js +126 -0
  68. package/dist/cjs/chain/orders.test.js +69 -0
  69. package/dist/cjs/chain/signers.js +22 -0
  70. package/dist/cjs/chain/signers.test.js +15 -0
  71. package/dist/cjs/chain/token.js +147 -0
  72. package/dist/cjs/chain/token.test.js +71 -0
  73. package/dist/cjs/chain/tx.js +103 -0
  74. package/dist/cjs/constants.js +6 -0
  75. package/dist/cjs/constants.test.js +31 -0
  76. package/dist/cjs/events.js +75 -0
  77. package/dist/cjs/events.test.js +384 -0
  78. package/dist/cjs/generated/accounts/config.js +79 -0
  79. package/dist/cjs/generated/accounts/index.js +28 -0
  80. package/dist/cjs/generated/accounts/maker.js +71 -0
  81. package/dist/cjs/generated/accounts/market.js +93 -0
  82. package/dist/cjs/generated/accounts/oracle.js +85 -0
  83. package/dist/cjs/generated/accounts/position.js +89 -0
  84. package/dist/cjs/generated/errors/actaContract.js +154 -0
  85. package/dist/cjs/generated/errors/index.js +24 -0
  86. package/dist/cjs/generated/index.js +28 -0
  87. package/dist/cjs/generated/instructions/changeOracleSource.js +81 -0
  88. package/dist/cjs/generated/instructions/closeMarket.js +83 -0
  89. package/dist/cjs/generated/instructions/closeOracle.js +79 -0
  90. package/dist/cjs/generated/instructions/createMarket.js +116 -0
  91. package/dist/cjs/generated/instructions/createOracle.js +99 -0
  92. package/dist/cjs/generated/instructions/depositFundsToPosition.js +101 -0
  93. package/dist/cjs/generated/instructions/depositPremium.js +96 -0
  94. package/dist/cjs/generated/instructions/finalizeMarket.js +91 -0
  95. package/dist/cjs/generated/instructions/index.js +43 -0
  96. package/dist/cjs/generated/instructions/initializeConfig.js +108 -0
  97. package/dist/cjs/generated/instructions/liquidatePosition.js +107 -0
  98. package/dist/cjs/generated/instructions/openPosition.js +154 -0
  99. package/dist/cjs/generated/instructions/registerMaker.js +90 -0
  100. package/dist/cjs/generated/instructions/setOracleConfig.js +80 -0
  101. package/dist/cjs/generated/instructions/settlePosition.js +104 -0
  102. package/dist/cjs/generated/instructions/topupFeeFund.js +96 -0
  103. package/dist/cjs/generated/instructions/updateConfig.js +86 -0
  104. package/dist/cjs/generated/instructions/updateMakerQuoteSigning.js +79 -0
  105. package/dist/cjs/generated/instructions/updateMarketOracles.js +96 -0
  106. package/dist/cjs/generated/instructions/updateOraclePrice.js +89 -0
  107. package/dist/cjs/generated/instructions/withdrawFromFeeFund.js +96 -0
  108. package/dist/cjs/generated/instructions/withdrawPremium.js +96 -0
  109. package/dist/cjs/generated/programs/actaContract.js +108 -0
  110. package/dist/cjs/generated/programs/index.js +24 -0
  111. package/dist/cjs/generated/shared/index.js +94 -0
  112. package/dist/cjs/generated/types/actaEvent.js +342 -0
  113. package/dist/cjs/generated/types/eventKind.js +45 -0
  114. package/dist/cjs/generated/types/index.js +27 -0
  115. package/dist/cjs/generated/types/positionStatus.js +31 -0
  116. package/dist/cjs/generated/types/positionType.js +28 -0
  117. package/dist/cjs/idl/acta_contract.json +2329 -0
  118. package/dist/cjs/idl/hash.js +4 -0
  119. package/dist/cjs/index.js +84 -0
  120. package/dist/cjs/nonce.js +93 -0
  121. package/dist/cjs/package.json +3 -0
  122. package/dist/cjs/types/index.js +18 -0
  123. package/dist/cjs/types/orderId.js +40 -0
  124. package/dist/cjs/types/orders.js +10 -0
  125. package/dist/cjs/ws/apy.js +106 -0
  126. package/dist/cjs/ws/apy.test.js +29 -0
  127. package/dist/cjs/ws/auth.js +104 -0
  128. package/dist/cjs/ws/client.handshake.integration.test.js +69 -0
  129. package/dist/cjs/ws/client.js +861 -0
  130. package/dist/cjs/ws/client.test.js +230 -0
  131. package/dist/cjs/ws/discovery.js +48 -0
  132. package/dist/cjs/ws/flows.js +101 -0
  133. package/dist/cjs/ws/flows.test.js +85 -0
  134. package/dist/cjs/ws/index.js +23 -0
  135. package/dist/cjs/ws/sponsoredTx.js +95 -0
  136. package/dist/cjs/ws/types.js +14 -0
  137. package/dist/cjs/ws/wirePolicy.js +34 -0
  138. package/dist/constants.d.ts +2 -0
  139. package/dist/constants.js +3 -0
  140. package/dist/constants.test.d.ts +1 -0
  141. package/dist/constants.test.js +29 -0
  142. package/dist/events.d.ts +15 -0
  143. package/dist/events.js +64 -0
  144. package/dist/events.test.d.ts +1 -0
  145. package/dist/events.test.js +382 -0
  146. package/dist/generated/accounts/config.d.ts +47 -0
  147. package/dist/generated/accounts/config.js +68 -0
  148. package/dist/generated/accounts/index.d.ts +12 -0
  149. package/dist/generated/accounts/index.js +12 -0
  150. package/dist/generated/accounts/maker.d.ts +39 -0
  151. package/dist/generated/accounts/maker.js +60 -0
  152. package/dist/generated/accounts/market.d.ts +61 -0
  153. package/dist/generated/accounts/market.js +82 -0
  154. package/dist/generated/accounts/oracle.d.ts +53 -0
  155. package/dist/generated/accounts/oracle.js +74 -0
  156. package/dist/generated/accounts/position.d.ts +57 -0
  157. package/dist/generated/accounts/position.js +78 -0
  158. package/dist/generated/errors/actaContract.d.ts +103 -0
  159. package/dist/generated/errors/actaContract.js +149 -0
  160. package/dist/generated/errors/index.d.ts +8 -0
  161. package/dist/generated/errors/index.js +8 -0
  162. package/dist/generated/index.d.ts +12 -0
  163. package/dist/generated/index.js +12 -0
  164. package/dist/generated/instructions/changeOracleSource.d.ts +50 -0
  165. package/dist/generated/instructions/changeOracleSource.js +72 -0
  166. package/dist/generated/instructions/closeMarket.d.ts +58 -0
  167. package/dist/generated/instructions/closeMarket.js +74 -0
  168. package/dist/generated/instructions/closeOracle.d.ts +48 -0
  169. package/dist/generated/instructions/closeOracle.js +70 -0
  170. package/dist/generated/instructions/createMarket.d.ts +90 -0
  171. package/dist/generated/instructions/createMarket.js +107 -0
  172. package/dist/generated/instructions/createOracle.d.ts +71 -0
  173. package/dist/generated/instructions/createOracle.js +90 -0
  174. package/dist/generated/instructions/depositFundsToPosition.d.ts +73 -0
  175. package/dist/generated/instructions/depositFundsToPosition.js +92 -0
  176. package/dist/generated/instructions/depositPremium.d.ts +62 -0
  177. package/dist/generated/instructions/depositPremium.js +87 -0
  178. package/dist/generated/instructions/finalizeMarket.d.ts +63 -0
  179. package/dist/generated/instructions/finalizeMarket.js +82 -0
  180. package/dist/generated/instructions/index.d.ts +27 -0
  181. package/dist/generated/instructions/index.js +27 -0
  182. package/dist/generated/instructions/initializeConfig.d.ts +75 -0
  183. package/dist/generated/instructions/initializeConfig.js +99 -0
  184. package/dist/generated/instructions/liquidatePosition.d.ts +78 -0
  185. package/dist/generated/instructions/liquidatePosition.js +98 -0
  186. package/dist/generated/instructions/openPosition.d.ts +130 -0
  187. package/dist/generated/instructions/openPosition.js +145 -0
  188. package/dist/generated/instructions/registerMaker.d.ts +57 -0
  189. package/dist/generated/instructions/registerMaker.js +81 -0
  190. package/dist/generated/instructions/setOracleConfig.d.ts +53 -0
  191. package/dist/generated/instructions/setOracleConfig.js +71 -0
  192. package/dist/generated/instructions/settlePosition.d.ts +78 -0
  193. package/dist/generated/instructions/settlePosition.js +95 -0
  194. package/dist/generated/instructions/topupFeeFund.d.ts +67 -0
  195. package/dist/generated/instructions/topupFeeFund.js +87 -0
  196. package/dist/generated/instructions/updateConfig.d.ts +58 -0
  197. package/dist/generated/instructions/updateConfig.js +77 -0
  198. package/dist/generated/instructions/updateMakerQuoteSigning.d.ts +47 -0
  199. package/dist/generated/instructions/updateMakerQuoteSigning.js +70 -0
  200. package/dist/generated/instructions/updateMarketOracles.d.ts +65 -0
  201. package/dist/generated/instructions/updateMarketOracles.js +87 -0
  202. package/dist/generated/instructions/updateOraclePrice.d.ts +55 -0
  203. package/dist/generated/instructions/updateOraclePrice.js +80 -0
  204. package/dist/generated/instructions/withdrawFromFeeFund.d.ts +62 -0
  205. package/dist/generated/instructions/withdrawFromFeeFund.js +87 -0
  206. package/dist/generated/instructions/withdrawPremium.d.ts +62 -0
  207. package/dist/generated/instructions/withdrawPremium.js +87 -0
  208. package/dist/generated/programs/actaContract.d.ts +83 -0
  209. package/dist/generated/programs/actaContract.js +104 -0
  210. package/dist/generated/programs/index.d.ts +8 -0
  211. package/dist/generated/programs/index.js +8 -0
  212. package/dist/generated/shared/index.d.ts +49 -0
  213. package/dist/generated/shared/index.js +86 -0
  214. package/dist/generated/types/actaEvent.d.ts +249 -0
  215. package/dist/generated/types/actaEvent.js +335 -0
  216. package/dist/generated/types/eventKind.d.ts +33 -0
  217. package/dist/generated/types/eventKind.js +39 -0
  218. package/dist/generated/types/index.d.ts +11 -0
  219. package/dist/generated/types/index.js +11 -0
  220. package/dist/generated/types/positionStatus.d.ts +19 -0
  221. package/dist/generated/types/positionStatus.js +25 -0
  222. package/dist/generated/types/positionType.d.ts +16 -0
  223. package/dist/generated/types/positionType.js +22 -0
  224. package/dist/idl/acta_contract.json +2329 -0
  225. package/dist/idl/hash.d.ts +1 -0
  226. package/dist/idl/hash.js +1 -0
  227. package/dist/index.d.ts +109 -0
  228. package/dist/index.js +34 -0
  229. package/dist/nonce.d.ts +29 -0
  230. package/dist/nonce.js +89 -0
  231. package/dist/types/index.d.ts +2 -0
  232. package/dist/types/index.js +2 -0
  233. package/dist/types/orderId.d.ts +13 -0
  234. package/dist/types/orderId.js +35 -0
  235. package/dist/types/orders.d.ts +9 -0
  236. package/dist/types/orders.js +9 -0
  237. package/dist/ws/apy.d.ts +79 -0
  238. package/dist/ws/apy.js +98 -0
  239. package/dist/ws/apy.test.d.ts +1 -0
  240. package/dist/ws/apy.test.js +27 -0
  241. package/dist/ws/auth.d.ts +67 -0
  242. package/dist/ws/auth.js +98 -0
  243. package/dist/ws/client.d.ts +263 -0
  244. package/dist/ws/client.handshake.integration.test.d.ts +1 -0
  245. package/dist/ws/client.handshake.integration.test.js +64 -0
  246. package/dist/ws/client.js +857 -0
  247. package/dist/ws/client.test.d.ts +1 -0
  248. package/dist/ws/client.test.js +228 -0
  249. package/dist/ws/discovery.d.ts +13 -0
  250. package/dist/ws/discovery.js +44 -0
  251. package/dist/ws/flows.d.ts +44 -0
  252. package/dist/ws/flows.js +96 -0
  253. package/dist/ws/flows.test.d.ts +1 -0
  254. package/dist/ws/flows.test.js +83 -0
  255. package/dist/ws/index.d.ts +7 -0
  256. package/dist/ws/index.js +7 -0
  257. package/dist/ws/sponsoredTx.d.ts +39 -0
  258. package/dist/ws/sponsoredTx.js +92 -0
  259. package/dist/ws/types.d.ts +900 -0
  260. package/dist/ws/types.js +13 -0
  261. package/dist/ws/wirePolicy.d.ts +12 -0
  262. package/dist/ws/wirePolicy.js +30 -0
  263. package/package.json +87 -0
@@ -0,0 +1,861 @@
1
+ "use strict";
2
+ /** Acta WebSocket client (rfq-server). */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.ActaWsClient = void 0;
5
+ const flows_1 = require("./flows");
6
+ const wirePolicy_1 = require("./wirePolicy");
7
+ function formatServerError(error) {
8
+ if (error.type === "generic") {
9
+ return `${error.data.code}: ${error.data.message}`;
10
+ }
11
+ if ("data" in error) {
12
+ const payload = typeof error.data === "string" ? error.data : JSON.stringify(error.data);
13
+ return `${error.type}: ${payload}`;
14
+ }
15
+ return error.type;
16
+ }
17
+ class TypedEventEmitter {
18
+ listeners = new Map();
19
+ on(event, listener) {
20
+ const set = this.listeners.get(event) ?? new Set();
21
+ set.add(listener);
22
+ this.listeners.set(event, set);
23
+ return this;
24
+ }
25
+ once(event, listener) {
26
+ const wrapped = ((...args) => {
27
+ this.off(event, wrapped);
28
+ listener(...args);
29
+ });
30
+ return this.on(event, wrapped);
31
+ }
32
+ off(event, listener) {
33
+ const set = this.listeners.get(event);
34
+ set?.delete(listener);
35
+ if (set && set.size === 0)
36
+ this.listeners.delete(event);
37
+ return this;
38
+ }
39
+ removeAllListeners(event) {
40
+ if (event === undefined) {
41
+ this.listeners.clear();
42
+ }
43
+ else {
44
+ this.listeners.delete(event);
45
+ }
46
+ return this;
47
+ }
48
+ emit(event, ...args) {
49
+ const set = this.listeners.get(event);
50
+ if (!set || set.size === 0)
51
+ return false;
52
+ for (const listener of Array.from(set)) {
53
+ listener(...args);
54
+ }
55
+ return true;
56
+ }
57
+ }
58
+ const WS_CONNECTING = 0;
59
+ const WS_OPEN = 1;
60
+ function defaultSocketFactory() {
61
+ const WsCtor = globalThis.WebSocket;
62
+ if (!WsCtor) {
63
+ throw new Error("No global WebSocket available. Provide `makeSocket` (e.g. using the `ws` package in Node).");
64
+ }
65
+ return (url) => new WsCtor(url);
66
+ }
67
+ function getCloseInfo(ev) {
68
+ if (!ev || typeof ev !== "object")
69
+ return {};
70
+ const rec = ev;
71
+ return {
72
+ code: typeof rec.code === "number" ? rec.code : undefined,
73
+ reason: typeof rec.reason === "string" ? rec.reason : undefined,
74
+ };
75
+ }
76
+ class ActaWsClient extends TypedEventEmitter {
77
+ ws = null;
78
+ options;
79
+ authProvider = null;
80
+ authRequested = false;
81
+ startAuthSent = false;
82
+ connectionState = "disconnected";
83
+ sessionId = null;
84
+ helloSent = false;
85
+ welcomeReceived = false;
86
+ pendingMessages = [];
87
+ reconnectAttempts = 0;
88
+ reconnectTimer = null;
89
+ pingTimer = null;
90
+ shouldReconnect = true;
91
+ subscribedChannels = new Set(["rfqs"]);
92
+ subscribedMarkets = new Set();
93
+ hasMarketScope = false;
94
+ state = {
95
+ stats: null,
96
+ activeRfqs: new Map(),
97
+ myActiveRfqs: new Map(),
98
+ positions: new Map(),
99
+ recentTrades: [],
100
+ markets: new Map(),
101
+ };
102
+ constructor(options) {
103
+ super();
104
+ this.options = {
105
+ protocolVersion: "1.0.0",
106
+ features: [],
107
+ autoReconnect: true,
108
+ reconnectDelay: 1000,
109
+ maxReconnectDelay: 30_000,
110
+ reconnectJitterRatio: 0.2,
111
+ pingInterval: 30_000,
112
+ maxPendingMessages: 100,
113
+ pendingMessagesOverflowPolicy: "drop_oldest",
114
+ debug: false,
115
+ makeSocket: options.makeSocket ?? defaultSocketFactory(),
116
+ ...options,
117
+ };
118
+ this.options.maxPendingMessages = Math.max(0, Math.floor(this.options.maxPendingMessages));
119
+ this.options.reconnectJitterRatio = Math.min(1, Math.max(0, this.options.reconnectJitterRatio));
120
+ this.shouldReconnect = this.options.autoReconnect;
121
+ }
122
+ connectAnonymous() {
123
+ this.authProvider = null;
124
+ this.authRequested = false;
125
+ this.shouldReconnect = this.options.autoReconnect;
126
+ this.doConnect();
127
+ }
128
+ connect(authProvider) {
129
+ this.authProvider = authProvider;
130
+ this.authRequested = false;
131
+ this.shouldReconnect = this.options.autoReconnect;
132
+ this.doConnect();
133
+ }
134
+ connectAndAuthenticate(authProvider) {
135
+ this.authProvider = authProvider;
136
+ this.authRequested = true;
137
+ this.shouldReconnect = this.options.autoReconnect;
138
+ if (this.ws?.readyState === WS_OPEN) {
139
+ if (this.welcomeReceived && !this.startAuthSent) {
140
+ void this.sendStartAuth().catch((err) => {
141
+ this.emit("error", err);
142
+ this.setConnectionState("error");
143
+ });
144
+ }
145
+ return;
146
+ }
147
+ this.doConnect();
148
+ }
149
+ async authenticate(authProvider) {
150
+ this.authProvider = authProvider;
151
+ this.authRequested = true;
152
+ if (this.ws?.readyState === WS_OPEN) {
153
+ if (this.welcomeReceived && !this.startAuthSent) {
154
+ await this.sendStartAuth();
155
+ }
156
+ return;
157
+ }
158
+ if (!this.ws) {
159
+ throw new Error("WebSocket is not connected");
160
+ }
161
+ }
162
+ disconnect() {
163
+ this.shouldReconnect = false;
164
+ this.cleanup();
165
+ }
166
+ getConnectionState() {
167
+ return this.connectionState;
168
+ }
169
+ isAuthenticated() {
170
+ return this.connectionState === "authenticated";
171
+ }
172
+ getSessionId() {
173
+ return this.sessionId;
174
+ }
175
+ async createRfq(request) {
176
+ this.ensureAuthenticated();
177
+ this.send({
178
+ type: "RfqRequest",
179
+ data: {
180
+ market: request.market,
181
+ position_type: request.position_type,
182
+ strike: request.strike,
183
+ quantity: request.quantity,
184
+ timeout_seconds: request.timeoutSeconds ?? 30,
185
+ client_request_id: request.clientRequestId,
186
+ },
187
+ });
188
+ }
189
+ async acceptQuote(rfqId, maker, orderIdHex) {
190
+ this.ensureAuthenticated();
191
+ this.send({
192
+ type: "AcceptQuote",
193
+ data: { rfq_id: rfqId, maker, order_id: orderIdHex },
194
+ });
195
+ }
196
+ /**
197
+ * Convenience: build and send `AcceptQuote` from a raw 32-byte `orderId`.
198
+ */
199
+ async acceptQuoteByOrderId(args) {
200
+ const msg = (0, flows_1.buildAcceptQuoteMessage)({
201
+ rfqId: args.rfqId,
202
+ maker: args.maker,
203
+ orderId: args.orderId,
204
+ });
205
+ return await this.acceptQuote(args.rfqId, args.maker, msg.order_id);
206
+ }
207
+ /**
208
+ * Submit a partially-signed sponsored transaction back to the server.
209
+ *
210
+ * `txBase64` must be a base64-encoded `VersionedTransaction` (v0) signed by the taker.
211
+ */
212
+ async submitSignedSponsoredTx(args) {
213
+ this.ensureAuthenticated();
214
+ this.send({
215
+ type: "SubmitSignedSponsoredTx",
216
+ data: { order_id: args.orderIdHex, tx_base64: args.txBase64 },
217
+ });
218
+ }
219
+ getPositions() {
220
+ this.ensureAuthenticated();
221
+ this.send({ type: "GetPositions" });
222
+ }
223
+ getMarkets() {
224
+ this.send({ type: "GetMarkets" });
225
+ }
226
+ getMarketDescriptors(args) {
227
+ const data = {
228
+ active_only: args?.active_only ?? true,
229
+ };
230
+ this.send({ type: "GetMarketDescriptors", data });
231
+ }
232
+ getExpiries(args) {
233
+ this.send({
234
+ type: "GetExpiries",
235
+ data: {
236
+ underlying_mint: args?.underlying_mint,
237
+ quote_mint: args?.quote_mint,
238
+ is_put: args?.is_put ?? null,
239
+ },
240
+ });
241
+ }
242
+ getTokens(args) {
243
+ const data = {
244
+ active_only: args?.active_only ?? true,
245
+ };
246
+ this.send({ type: "GetTokens", data });
247
+ }
248
+ getMyActiveRfqs() {
249
+ this.ensureAuthenticated();
250
+ this.send({ type: "GetMyActiveRfqs" });
251
+ }
252
+ getActiveRfqs() {
253
+ this.send({ type: "GetActiveRfqs" });
254
+ }
255
+ getOrderStatus(orderIdHex) {
256
+ this.ensureAuthenticated();
257
+ this.send({ type: "GetOrderStatus", data: { order_id: orderIdHex } });
258
+ }
259
+ cancelRfq(rfqId) {
260
+ this.ensureAuthenticated();
261
+ this.send({ type: "CancelRfq", data: { rfq_id: rfqId } });
262
+ }
263
+ submitQuote(quote) {
264
+ this.ensureAuthenticated();
265
+ this.send({ type: "Quote", data: quote });
266
+ }
267
+ /**
268
+ * Convenience: sign 32-byte `orderId` and send `Quote`.
269
+ *
270
+ * Maker constructs the full on-chain order (incl. nonce), computes `orderId`,
271
+ * signs it, and sends the signature + orderId over WS.
272
+ */
273
+ async submitQuoteSigned(args) {
274
+ (0, wirePolicy_1.assertWsU64Safe)(args.strike, "strike");
275
+ (0, wirePolicy_1.assertWsU64Safe)(args.price, "price");
276
+ (0, wirePolicy_1.assertWsU64Safe)(args.validUntil, "validUntil");
277
+ (0, wirePolicy_1.assertWsU64Safe)(args.nonce, "nonce");
278
+ const quote = await (0, flows_1.buildSignedQuoteMessage)({
279
+ rfqId: args.rfqId,
280
+ strike: args.strike,
281
+ price: args.price,
282
+ validUntil: args.validUntil,
283
+ nonce: args.nonce,
284
+ orderId: args.orderId,
285
+ makerSigner: args.makerSigner,
286
+ });
287
+ this.submitQuote(quote);
288
+ }
289
+ cancelQuote(rfqId) {
290
+ this.ensureAuthenticated();
291
+ this.send({ type: "CancelQuote", data: { rfq_id: rfqId } });
292
+ }
293
+ subscribe(channels, markets) {
294
+ this.ensureAuthenticated();
295
+ for (const c of channels)
296
+ this.subscribedChannels.add(c);
297
+ if (markets) {
298
+ this.hasMarketScope = true;
299
+ this.subscribedMarkets = new Set(markets);
300
+ }
301
+ this.send({
302
+ type: "Subscribe",
303
+ data: this.hasMarketScope
304
+ ? { channels, markets: Array.from(this.subscribedMarkets) }
305
+ : { channels },
306
+ });
307
+ }
308
+ unsubscribe(channels) {
309
+ this.ensureAuthenticated();
310
+ for (const c of channels)
311
+ this.subscribedChannels.delete(c);
312
+ this.send({
313
+ type: "Unsubscribe",
314
+ data: { channels },
315
+ });
316
+ }
317
+ ping() {
318
+ if (this.ws?.readyState === WS_OPEN) {
319
+ this.send({ type: "Ping" });
320
+ }
321
+ }
322
+ doConnect() {
323
+ if (this.ws) {
324
+ this.cleanup();
325
+ }
326
+ this.setConnectionState("connecting");
327
+ this.emit("connecting");
328
+ const endpoint = this.options.role === "maker" ? "/ws/maker" : "/ws/taker";
329
+ const url = `${this.options.url}${endpoint}`;
330
+ this.log(`Connecting to ${url}`);
331
+ const ws = this.options.makeSocket(url);
332
+ this.ws = ws;
333
+ this.helloSent = false;
334
+ this.welcomeReceived = false;
335
+ this.startAuthSent = false;
336
+ this.pendingMessages = [];
337
+ ws.onopen = () => {
338
+ this.log("WebSocket connected");
339
+ this.reconnectAttempts = 0;
340
+ this.sendHello();
341
+ this.emit("connected");
342
+ this.startPingInterval();
343
+ };
344
+ ws.onmessage = (event) => {
345
+ try {
346
+ const parsed = JSON.parse(event.data);
347
+ this.handleMessage(parsed);
348
+ }
349
+ catch (err) {
350
+ this.log("Failed to parse message:", err);
351
+ }
352
+ };
353
+ ws.onclose = (ev) => {
354
+ const info = getCloseInfo(ev);
355
+ const code = typeof info.code === "number" ? info.code : 1000;
356
+ const reason = typeof info.reason === "string" ? info.reason : "";
357
+ this.log(`WebSocket closed: ${code} ${reason}`);
358
+ this.cleanup();
359
+ this.emit("disconnected", code, reason);
360
+ if (this.shouldReconnect) {
361
+ this.scheduleReconnect();
362
+ }
363
+ };
364
+ ws.onerror = (ev) => {
365
+ this.log("WebSocket error:", ev);
366
+ this.emit("error", new Error("WebSocket error"));
367
+ if (this.shouldReconnect) {
368
+ this.cleanup();
369
+ this.scheduleReconnect();
370
+ }
371
+ };
372
+ }
373
+ handleMessage(message) {
374
+ this.log("Received:", message.type);
375
+ this.emit("message", message);
376
+ switch (message.type) {
377
+ case "Welcome":
378
+ this.welcomeReceived = true;
379
+ this.emit("welcome", message.data);
380
+ this.flushPendingMessages();
381
+ if (this.authRequested && this.authProvider && !this.startAuthSent) {
382
+ void this.sendStartAuth().catch((err) => {
383
+ this.emit("error", err);
384
+ this.setConnectionState("error");
385
+ });
386
+ }
387
+ break;
388
+ case "VersionMismatch":
389
+ this.emit("versionMismatch", message.data);
390
+ this.stopAutoReconnect();
391
+ this.setConnectionState("error");
392
+ if (this.ws &&
393
+ (this.ws.readyState === WS_OPEN ||
394
+ this.ws.readyState === WS_CONNECTING)) {
395
+ try {
396
+ this.ws.close(1002, "version_mismatch");
397
+ }
398
+ catch {
399
+ // ignore
400
+ }
401
+ }
402
+ break;
403
+ case "AuthRequest":
404
+ void this.handleAuthRequest(message.data.challenge);
405
+ break;
406
+ case "AuthSuccess":
407
+ this.handleAuthSuccess(message.data.session_id);
408
+ break;
409
+ case "AuthError":
410
+ this.handleAuthError(message.data.reason);
411
+ break;
412
+ case "Snapshot":
413
+ this.handleSnapshot(message.data);
414
+ break;
415
+ case "Positions":
416
+ this.handlePositions(message.data.positions ?? []);
417
+ break;
418
+ case "Markets":
419
+ this.handleMarkets(message.data.markets ?? []);
420
+ break;
421
+ case "MarketDescriptors":
422
+ this.emit("marketDescriptors", message.data.markets ?? []);
423
+ break;
424
+ case "Expiries":
425
+ this.emit("expiries", message.data.expiries_ts ?? []);
426
+ break;
427
+ case "Tokens":
428
+ this.emit("tokens", {
429
+ underlyings: message.data.underlyings ?? [],
430
+ quotesByUnderlying: message.data.quotes_by_underlying ?? {},
431
+ });
432
+ break;
433
+ case "Subscriptions":
434
+ this.emit("subscriptions", message.data);
435
+ break;
436
+ case "ActiveRfqs":
437
+ this.state.activeRfqs.clear();
438
+ for (const rfq of message.data.rfqs) {
439
+ this.state.activeRfqs.set(rfq.rfq_id, rfq);
440
+ }
441
+ this.emit("activeRfqs", message.data.rfqs);
442
+ break;
443
+ case "MyActiveRfqs":
444
+ this.handleMyActiveRfqs(message.data);
445
+ break;
446
+ case "OrderStatus":
447
+ this.handleOrderStatus(message.data);
448
+ break;
449
+ case "StatsUpdate":
450
+ this.handleStatsUpdate(message.data.stats);
451
+ break;
452
+ case "RfqBroadcast":
453
+ // Keep local RFQ state reasonably fresh even without a new snapshot.
454
+ if (!this.state.activeRfqs.has(message.data.rfq_id)) {
455
+ this.state.activeRfqs.set(message.data.rfq_id, {
456
+ rfq_id: message.data.rfq_id,
457
+ market: message.data.market.market_pda,
458
+ position_type: message.data.position_type,
459
+ strike: message.data.strike,
460
+ quantity: message.data.quantity,
461
+ expires_at: message.data.expires_at,
462
+ quotes_count: 0,
463
+ best_price: null,
464
+ order_options: message.data.order_options,
465
+ });
466
+ }
467
+ this.emit("rfqBroadcast", message.data);
468
+ break;
469
+ case "RfqCreated":
470
+ this.emit("rfqCreated", message.data);
471
+ break;
472
+ case "RfqClosed":
473
+ this.state.activeRfqs.delete(message.data.rfq_id);
474
+ this.emit("rfqClosed", message.data);
475
+ break;
476
+ case "QuoteReceived":
477
+ {
478
+ const rfq = this.state.activeRfqs.get(message.data.rfq_id);
479
+ if (rfq) {
480
+ const nextCount = rfq.quotes_count + 1;
481
+ const nextBest = rfq.best_price === null
482
+ ? message.data.price
483
+ : Math.max(rfq.best_price, message.data.price);
484
+ this.state.activeRfqs.set(message.data.rfq_id, {
485
+ ...rfq,
486
+ quotes_count: nextCount,
487
+ best_price: nextBest,
488
+ });
489
+ }
490
+ this.emit("quoteReceived", message.data);
491
+ }
492
+ break;
493
+ case "QuotesUpdate":
494
+ {
495
+ const rfq = this.state.activeRfqs.get(message.data.rfq_id);
496
+ if (rfq) {
497
+ const prices = message.data.quotes.map((q) => q.price);
498
+ const nextBest = prices.length === 0 ? null : Math.max(...prices);
499
+ this.state.activeRfqs.set(message.data.rfq_id, {
500
+ ...rfq,
501
+ quotes_count: message.data.quotes.length,
502
+ best_price: nextBest,
503
+ });
504
+ }
505
+ this.emit("quotesUpdate", message.data);
506
+ }
507
+ break;
508
+ case "QuoteAcknowledged":
509
+ this.emit("quoteAcknowledged", message.data);
510
+ break;
511
+ case "QuoteBestStatus":
512
+ this.emit("quoteBestStatus", message.data);
513
+ break;
514
+ case "QuoteOutbid":
515
+ this.emit("quoteOutbid", message.data);
516
+ break;
517
+ case "QuoteRefreshRequested":
518
+ this.emit("quoteRefreshRequested", message.data);
519
+ break;
520
+ case "QuoteSelected":
521
+ this.emit("quoteSelected", message.data);
522
+ break;
523
+ case "QuoteFilled":
524
+ this.emit("quoteFilled", message.data);
525
+ break;
526
+ case "QuoteCancelled":
527
+ this.emit("quoteCancelled", message.data);
528
+ break;
529
+ case "RfqAvailableAgain":
530
+ this.emit("rfqAvailableAgain", message.data);
531
+ break;
532
+ case "QuoteExpired":
533
+ this.emit("quoteExpired", message.data);
534
+ break;
535
+ case "IndicativePrices":
536
+ this.emit("indicativePrices", message.data);
537
+ break;
538
+ case "IndicativePricesRequest":
539
+ this.emit("indicativePricesRequest", message.data);
540
+ break;
541
+ case "OrderAccepted":
542
+ this.emit("orderAccepted", message.data.order_id);
543
+ break;
544
+ case "SponsoredTxToSign":
545
+ this.emit("sponsoredTxToSign", message.data.order_id, message.data.tx_base64, message.data.signature_deadline);
546
+ break;
547
+ case "OrderSubmitted":
548
+ this.emit("orderSubmitted", message.data.order_id, message.data.tx_signature);
549
+ break;
550
+ case "OrderConfirmed":
551
+ this.emit("orderConfirmed", message.data.order_id, message.data.position_pda);
552
+ break;
553
+ case "OrderFailed":
554
+ this.emit("orderFailed", message.data.order_id, message.data.reason);
555
+ break;
556
+ case "TradeExecuted":
557
+ this.handleTradeExecuted(message.data);
558
+ break;
559
+ case "PositionUpdated":
560
+ this.handlePositionUpdated(message.data);
561
+ break;
562
+ case "MarketCreated":
563
+ this.state.markets.set(message.data.pda, message.data);
564
+ this.emit("marketCreated", message.data);
565
+ break;
566
+ case "MarketFinalized":
567
+ this.emit("marketFinalized", message.data.market_pda, message.data.settlement_price);
568
+ break;
569
+ case "ChainEvent":
570
+ this.handleChainEvent(message.data);
571
+ break;
572
+ case "Pong":
573
+ break;
574
+ case "Error":
575
+ this.emit("error", new Error(formatServerError(message.data)));
576
+ break;
577
+ }
578
+ }
579
+ /** Taker-only: request current indicative prices for a market + position_type. */
580
+ getIndicativePrices(req) {
581
+ this.send({
582
+ type: "GetIndicativePrices",
583
+ data: req,
584
+ });
585
+ }
586
+ /** Maker-only: respond to an indicative request (unsigned, non-binding). */
587
+ sendIndicativePricesResponse(resp) {
588
+ this.ensureAuthenticated();
589
+ this.send({ type: "IndicativePricesResponse", data: resp });
590
+ }
591
+ async handleAuthRequest(challenge) {
592
+ this.setConnectionState("authenticating");
593
+ if (!this.authProvider) {
594
+ this.emit("error", new Error("No auth provider configured"));
595
+ return;
596
+ }
597
+ try {
598
+ const [pubkey, signature] = await Promise.all([
599
+ this.authProvider.getPublicKey(),
600
+ this.authProvider.signChallenge(challenge),
601
+ ]);
602
+ this.send({
603
+ type: "AuthChallenge",
604
+ data: { challenge, signature, pubkey },
605
+ });
606
+ }
607
+ catch (err) {
608
+ this.emit("error", err);
609
+ this.setConnectionState("error");
610
+ }
611
+ }
612
+ async sendStartAuth() {
613
+ if (!this.authProvider)
614
+ throw new Error("No auth provider configured");
615
+ this.startAuthSent = true;
616
+ const pubkey = await this.authProvider.getPublicKey();
617
+ this.send({ type: "StartAuth", data: { pubkey } });
618
+ }
619
+ sendHello() {
620
+ const hello = {
621
+ protocol_version: this.options.protocolVersion,
622
+ features: this.options.features ?? [],
623
+ client_name: this.options.clientName,
624
+ client_version: this.options.clientVersion,
625
+ };
626
+ this.send({ type: "Hello", data: hello });
627
+ }
628
+ flushPendingMessages() {
629
+ if (!this.welcomeReceived || this.pendingMessages.length === 0)
630
+ return;
631
+ const pending = this.pendingMessages;
632
+ this.pendingMessages = [];
633
+ for (const msg of pending) {
634
+ this.send(msg);
635
+ }
636
+ }
637
+ handleAuthSuccess(sessionId) {
638
+ this.sessionId = sessionId;
639
+ this.setConnectionState("authenticated");
640
+ this.emit("authenticated", sessionId);
641
+ if (this.subscribedChannels.size > 0) {
642
+ const channels = Array.from(this.subscribedChannels);
643
+ const data = this.hasMarketScope
644
+ ? { channels, markets: Array.from(this.subscribedMarkets) }
645
+ : { channels };
646
+ this.send({ type: "Subscribe", data });
647
+ }
648
+ }
649
+ handleAuthError(reason) {
650
+ this.setConnectionState("error");
651
+ this.emit("error", new Error(`Authentication failed: ${reason}`));
652
+ }
653
+ handleSnapshot(snapshot) {
654
+ this.state.stats = snapshot.stats;
655
+ this.state.activeRfqs.clear();
656
+ for (const rfq of snapshot.active_rfqs) {
657
+ this.state.activeRfqs.set(rfq.rfq_id, rfq);
658
+ }
659
+ this.state.myActiveRfqs.clear();
660
+ this.state.positions.clear();
661
+ for (const position of snapshot.positions ?? []) {
662
+ this.state.positions.set(position.pda, position);
663
+ }
664
+ this.state.recentTrades = snapshot.recent_trades ?? [];
665
+ this.state.markets.clear();
666
+ for (const market of snapshot.markets) {
667
+ this.state.markets.set(market.pda, market);
668
+ }
669
+ this.emit("snapshot", snapshot);
670
+ }
671
+ handleMyActiveRfqs(msg) {
672
+ this.state.myActiveRfqs.clear();
673
+ for (const rfq of msg.rfqs) {
674
+ this.state.myActiveRfqs.set(rfq.rfq_id, rfq);
675
+ }
676
+ this.emit("myActiveRfqs", msg);
677
+ }
678
+ handleOrderStatus(msg) {
679
+ this.emit("orderStatus", msg);
680
+ }
681
+ handlePositions(positions) {
682
+ this.state.positions.clear();
683
+ for (const position of positions) {
684
+ this.state.positions.set(position.pda, position);
685
+ }
686
+ this.emit("positions", positions);
687
+ }
688
+ handleMarkets(markets) {
689
+ this.state.markets.clear();
690
+ for (const market of markets) {
691
+ this.state.markets.set(market.pda, market);
692
+ }
693
+ this.emit("markets", markets);
694
+ }
695
+ handleStatsUpdate(stats) {
696
+ this.state.stats = stats;
697
+ this.emit("statsUpdate", stats);
698
+ }
699
+ handleTradeExecuted(data) {
700
+ this.state.recentTrades.unshift(data.trade);
701
+ this.state.recentTrades = this.state.recentTrades.slice(0, 50);
702
+ const delta = data.stats_delta ?? null;
703
+ if (delta && this.state.stats) {
704
+ if (delta.volume_added)
705
+ this.state.stats.total_volume_24h += delta.volume_added;
706
+ if (delta.trades_added)
707
+ this.state.stats.total_trades_24h += delta.trades_added;
708
+ if (delta.price_added)
709
+ this.state.stats.total_price_24h += delta.price_added;
710
+ }
711
+ this.emit("tradeExecuted", data.trade, delta);
712
+ }
713
+ handlePositionUpdated(data) {
714
+ this.state.positions.set(data.position.pda, data.position);
715
+ this.emit("positionUpdated", data.position, data.update_type);
716
+ }
717
+ handleChainEvent(event) {
718
+ this.emit("chainEvent", event);
719
+ switch (event.event_type) {
720
+ case "PositionOpened":
721
+ this.emit("positionOpened", event);
722
+ break;
723
+ case "MakerRegistered":
724
+ this.emit("makerRegistered", event);
725
+ break;
726
+ case "MarketCreated":
727
+ this.emit("chainMarketCreated", event);
728
+ break;
729
+ case "MarketFinalized":
730
+ this.emit("chainMarketFinalized", event);
731
+ break;
732
+ case "PositionSettled":
733
+ this.emit("positionSettled", event);
734
+ break;
735
+ }
736
+ }
737
+ send(message) {
738
+ if (this.ws?.readyState === WS_OPEN) {
739
+ if (!this.welcomeReceived && message.type !== "Hello") {
740
+ if (this.enqueuePendingMessage(message)) {
741
+ this.log("Queued until Welcome:", message.type);
742
+ }
743
+ return;
744
+ }
745
+ if (message.type === "Hello") {
746
+ if (this.helloSent)
747
+ return;
748
+ this.helloSent = true;
749
+ }
750
+ this.log("Sending:", message.type);
751
+ this.ws.send(JSON.stringify(message));
752
+ }
753
+ else {
754
+ this.log("Cannot send, WebSocket not open");
755
+ }
756
+ }
757
+ ensureAuthenticated() {
758
+ if (this.connectionState !== "authenticated") {
759
+ throw new Error("Client is not authenticated");
760
+ }
761
+ }
762
+ setConnectionState(state) {
763
+ if (this.connectionState !== state) {
764
+ this.connectionState = state;
765
+ this.emit("stateChange", state);
766
+ }
767
+ }
768
+ startPingInterval() {
769
+ this.stopPingInterval();
770
+ this.pingTimer = setInterval(() => this.ping(), this.options.pingInterval);
771
+ }
772
+ stopPingInterval() {
773
+ if (this.pingTimer) {
774
+ clearInterval(this.pingTimer);
775
+ this.pingTimer = null;
776
+ }
777
+ }
778
+ enqueuePendingMessage(message) {
779
+ const maxPending = this.options.maxPendingMessages;
780
+ if (this.pendingMessages.length < maxPending) {
781
+ this.pendingMessages.push(message);
782
+ return true;
783
+ }
784
+ switch (this.options.pendingMessagesOverflowPolicy) {
785
+ case "drop_oldest":
786
+ if (maxPending === 0) {
787
+ this.log("Dropping pending message (maxPendingMessages=0):", message.type);
788
+ return false;
789
+ }
790
+ this.pendingMessages.shift();
791
+ this.pendingMessages.push(message);
792
+ this.log("Pending queue full, dropped oldest and queued newest:", message.type);
793
+ return true;
794
+ case "drop_newest":
795
+ this.log("Pending queue full, dropping newest message:", message.type);
796
+ return false;
797
+ case "throw":
798
+ this.emit("error", new Error(`Pending queue overflow (maxPendingMessages=${maxPending}) for message type=${message.type}`));
799
+ return false;
800
+ }
801
+ }
802
+ stopAutoReconnect() {
803
+ this.shouldReconnect = false;
804
+ if (this.reconnectTimer) {
805
+ clearTimeout(this.reconnectTimer);
806
+ this.reconnectTimer = null;
807
+ }
808
+ }
809
+ scheduleReconnect() {
810
+ if (!this.shouldReconnect)
811
+ return;
812
+ if (this.reconnectTimer)
813
+ return;
814
+ const baseDelay = Math.min(this.options.reconnectDelay * Math.pow(2, this.reconnectAttempts), this.options.maxReconnectDelay);
815
+ const jitterRatio = this.options.reconnectJitterRatio;
816
+ const jitterFactor = 1 + (Math.random() * 2 - 1) * jitterRatio;
817
+ const delay = Math.min(this.options.maxReconnectDelay, Math.max(0, Math.round(baseDelay * jitterFactor)));
818
+ this.log(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts + 1})`);
819
+ this.reconnectTimer = setTimeout(() => {
820
+ this.reconnectTimer = null;
821
+ this.reconnectAttempts += 1;
822
+ this.doConnect();
823
+ }, delay);
824
+ }
825
+ cleanup() {
826
+ this.stopPingInterval();
827
+ if (this.reconnectTimer) {
828
+ clearTimeout(this.reconnectTimer);
829
+ this.reconnectTimer = null;
830
+ }
831
+ if (this.ws) {
832
+ this.ws.onopen = null;
833
+ this.ws.onmessage = null;
834
+ this.ws.onclose = null;
835
+ this.ws.onerror = null;
836
+ if (this.ws.readyState === WS_OPEN ||
837
+ this.ws.readyState === WS_CONNECTING) {
838
+ try {
839
+ this.ws.close();
840
+ }
841
+ catch {
842
+ // ignore
843
+ }
844
+ }
845
+ this.ws = null;
846
+ }
847
+ this.sessionId = null;
848
+ this.helloSent = false;
849
+ this.welcomeReceived = false;
850
+ this.startAuthSent = false;
851
+ this.pendingMessages = [];
852
+ this.setConnectionState("disconnected");
853
+ }
854
+ log(...args) {
855
+ if (this.options.debug) {
856
+ // eslint-disable-next-line no-console
857
+ console.log("[ActaWsClient]", ...args);
858
+ }
859
+ }
860
+ }
861
+ exports.ActaWsClient = ActaWsClient;