@tradelayerprotocol/tradelayer 1.9.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 (249) hide show
  1. package/.claude/settings.local.json +13 -0
  2. package/.claude/skills/tl-algo/SKILL.md +255 -0
  3. package/.gitattributes +2 -0
  4. package/.github/workflows/publish.yaml +26 -0
  5. package/4mm.js +163 -0
  6. package/LICENSE +21 -0
  7. package/NPMSwapRefactor.zip +0 -0
  8. package/README.md +217 -0
  9. package/address.sh +26 -0
  10. package/algoAPI.js +581 -0
  11. package/analyzepsbt.js +92 -0
  12. package/apiEx.js +99 -0
  13. package/bb_hyperscalper.js +290 -0
  14. package/bbo_demo.js +111 -0
  15. package/buyer.js +622 -0
  16. package/client.js +50 -0
  17. package/createTxTest.js +26 -0
  18. package/createWallet.js +75 -0
  19. package/daytrader.js +531 -0
  20. package/decodeTest.js +69 -0
  21. package/fundingManager.js +144 -0
  22. package/index.js +4 -0
  23. package/listener.js +27 -0
  24. package/litecoreTxBuilder.js +1128 -0
  25. package/mmEx.js +356 -0
  26. package/networks.js +51 -0
  27. package/orderbook.js +200 -0
  28. package/package.json +34 -0
  29. package/perTradeQueue.js +36 -0
  30. package/projectsTLNPMTLNPM/package-lock.json +162 -0
  31. package/projectsTLNPMTLNPM/package.json +5 -0
  32. package/quick.js +32 -0
  33. package/quickFut.js +37 -0
  34. package/quickSell.js +37 -0
  35. package/relayerClient.js +117 -0
  36. package/run4mm.js +80 -0
  37. package/run_bbo_tracker.js +241 -0
  38. package/seller.js +443 -0
  39. package/session.js +45 -0
  40. package/setup-lin-ltc.sh +139 -0
  41. package/setup-lin.sh +203 -0
  42. package/setup-win-ltc.bat +108 -0
  43. package/setup-win.bat +167 -0
  44. package/spam_screamer_futures.js +222 -0
  45. package/tradelayer.js/.gitattributes +2 -0
  46. package/tradelayer.js/README.md +2 -0
  47. package/tradelayer.js/oldTests/activationTest.js +6 -0
  48. package/tradelayer.js/oldTests/base58.test.js +23 -0
  49. package/tradelayer.js/oldTests/base64Decode.test.js +16 -0
  50. package/tradelayer.js/oldTests/blocksRefactor.js +140 -0
  51. package/tradelayer.js/oldTests/checkVestBalance.js +25 -0
  52. package/tradelayer.js/oldTests/consensusHashProto.js +151 -0
  53. package/tradelayer.js/oldTests/contractOrderbook.js +243 -0
  54. package/tradelayer.js/oldTests/createPayload.js +0 -0
  55. package/tradelayer.js/oldTests/createTestnetAddr.js +43 -0
  56. package/tradelayer.js/oldTests/decode.js +205 -0
  57. package/tradelayer.js/oldTests/decodeTest.js +50 -0
  58. package/tradelayer.js/oldTests/displayTallyMap.js +19 -0
  59. package/tradelayer.js/oldTests/encodeDecode.js +340 -0
  60. package/tradelayer.js/oldTests/expressTest.js +29 -0
  61. package/tradelayer.js/oldTests/extractBlocksVanilla.js +214 -0
  62. package/tradelayer.js/oldTests/extractBlocksVanillaa.js +179 -0
  63. package/tradelayer.js/oldTests/extractPubkeyTest.js +60 -0
  64. package/tradelayer.js/oldTests/fillInputCacheProto.js +111 -0
  65. package/tradelayer.js/oldTests/getRawTxTest.js +22 -0
  66. package/tradelayer.js/oldTests/indexTest.js +26 -0
  67. package/tradelayer.js/oldTests/initTokensTest.js +32 -0
  68. package/tradelayer.js/oldTests/interfaceChild.js +129 -0
  69. package/tradelayer.js/oldTests/listenerChild.js +112 -0
  70. package/tradelayer.js/oldTests/opdecode.js +26 -0
  71. package/tradelayer.js/oldTests/options.js +79 -0
  72. package/tradelayer.js/oldTests/optxtest.js +116 -0
  73. package/tradelayer.js/oldTests/optxtest1.js +64 -0
  74. package/tradelayer.js/oldTests/oracle.test.js +32 -0
  75. package/tradelayer.js/oldTests/orderbook.test.js +36 -0
  76. package/tradelayer.js/oldTests/parsing.js +93 -0
  77. package/tradelayer.js/oldTests/payload.js +13 -0
  78. package/tradelayer.js/oldTests/persistenceUnitTest.js +23 -0
  79. package/tradelayer.js/oldTests/property.test.js +53 -0
  80. package/tradelayer.js/oldTests/propertyLevel.js +75 -0
  81. package/tradelayer.js/oldTests/propertyTest.js +32 -0
  82. package/tradelayer.js/oldTests/queryAddressTest.js +17 -0
  83. package/tradelayer.js/oldTests/salter.js +14 -0
  84. package/tradelayer.js/oldTests/tally.js +81 -0
  85. package/tradelayer.js/oldTests/tally.test.js +48 -0
  86. package/tradelayer.js/oldTests/tally2.js +124 -0
  87. package/tradelayer.js/oldTests/tally3.js +142 -0
  88. package/tradelayer.js/oldTests/tallyDiag.js +38 -0
  89. package/tradelayer.js/oldTests/testGetRaw.js +40 -0
  90. package/tradelayer.js/oldTests/testHexConvert.js +47 -0
  91. package/tradelayer.js/oldTests/testNewEncoding.js +96 -0
  92. package/tradelayer.js/oldTests/testNewEncoding2.js +113 -0
  93. package/tradelayer.js/oldTests/testNewEncoding3 +112 -0
  94. package/tradelayer.js/oldTests/testNewEncoding3.js +168 -0
  95. package/tradelayer.js/oldTests/testOPReturn.js +102 -0
  96. package/tradelayer.js/oldTests/testPayload.js +23 -0
  97. package/tradelayer.js/oldTests/testRaw.js +50 -0
  98. package/tradelayer.js/oldTests/testSendTooMuch.js +20 -0
  99. package/tradelayer.js/oldTests/testTxBuild +28 -0
  100. package/tradelayer.js/oldTests/testTxBuild.js +42 -0
  101. package/tradelayer.js/oldTests/tokenOrderbook.js +243 -0
  102. package/tradelayer.js/oldTests/txUtilsA.js +515 -0
  103. package/tradelayer.js/oldTests/validityUnitTest.js +53 -0
  104. package/tradelayer.js/oldTests/vaults.js +72 -0
  105. package/tradelayer.js/oldTests/volumeIndex.js +117 -0
  106. package/tradelayer.js/oldTests/volumeIndex2.js +88 -0
  107. package/tradelayer.js/output_base64.txt +1 -0
  108. package/tradelayer.js/package-lock.json +9967 -0
  109. package/tradelayer.js/package.json +61 -0
  110. package/tradelayer.js/server/index.js +88 -0
  111. package/tradelayer.js/server/litecoind.exe +0 -0
  112. package/tradelayer.js/src/activation.js +303 -0
  113. package/tradelayer.js/src/adjuster.js +77 -0
  114. package/tradelayer.js/src/amm.js +400 -0
  115. package/tradelayer.js/src/base256.js +55 -0
  116. package/tradelayer.js/src/base94.js +79 -0
  117. package/tradelayer.js/src/channels.js +1163 -0
  118. package/tradelayer.js/src/clearing.js +3109 -0
  119. package/tradelayer.js/src/clearlist.js +364 -0
  120. package/tradelayer.js/src/client.js +295 -0
  121. package/tradelayer.js/src/consensus.js +613 -0
  122. package/tradelayer.js/src/contractRegistry.js +964 -0
  123. package/tradelayer.js/src/db.js +89 -0
  124. package/tradelayer.js/src/init.js +24 -0
  125. package/tradelayer.js/src/insurance.js +347 -0
  126. package/tradelayer.js/src/interface.js +218 -0
  127. package/tradelayer.js/src/interfaceExpress.js +178 -0
  128. package/tradelayer.js/src/iou.js +509 -0
  129. package/tradelayer.js/src/listener.js +226 -0
  130. package/tradelayer.js/src/logic.js +1702 -0
  131. package/tradelayer.js/src/main.js +927 -0
  132. package/tradelayer.js/src/marginMap.js +2165 -0
  133. package/tradelayer.js/src/options.js +126 -0
  134. package/tradelayer.js/src/oracle.js +394 -0
  135. package/tradelayer.js/src/orderbook.js +4123 -0
  136. package/tradelayer.js/src/persistence.js +554 -0
  137. package/tradelayer.js/src/property.js +411 -0
  138. package/tradelayer.js/src/reOrg.js +41 -0
  139. package/tradelayer.js/src/scaling.js +145 -0
  140. package/tradelayer.js/src/tally.js +1275 -0
  141. package/tradelayer.js/src/tradeHistoryManager.js +552 -0
  142. package/tradelayer.js/src/txDecoder.js +584 -0
  143. package/tradelayer.js/src/txEncoder.js +610 -0
  144. package/tradelayer.js/src/txIndex.js +502 -0
  145. package/tradelayer.js/src/txUtils.js +1392 -0
  146. package/tradelayer.js/src/types.js +429 -0
  147. package/tradelayer.js/src/validity.js +3077 -0
  148. package/tradelayer.js/src/vaults.js +430 -0
  149. package/tradelayer.js/src/vesting.js +491 -0
  150. package/tradelayer.js/src/volumeIndex.js +618 -0
  151. package/tradelayer.js/src/walletInterface.js +220 -0
  152. package/tradelayer.js/src/walletListener.js +665 -0
  153. package/tradelayer.js/tests/256decode.js +82 -0
  154. package/tradelayer.js/tests/UTXOracle.js +205 -0
  155. package/tradelayer.js/tests/base94test.js +23 -0
  156. package/tradelayer.js/tests/cancelTxTest.js +62 -0
  157. package/tradelayer.js/tests/contractInterfaceTest.js +48 -0
  158. package/tradelayer.js/tests/decimalTest.js +65 -0
  159. package/tradelayer.js/tests/decoderTest.js +100 -0
  160. package/tradelayer.js/tests/deltaCount.js +47 -0
  161. package/tradelayer.js/tests/deltaCount2.js +60 -0
  162. package/tradelayer.js/tests/interfaceTest.js +37 -0
  163. package/tradelayer.js/tests/mainTest.js +53 -0
  164. package/tradelayer.js/tests/makeActivationTest.js +24 -0
  165. package/tradelayer.js/tests/maxHeightTest.js +49 -0
  166. package/tradelayer.js/tests/reverseHash.js +72 -0
  167. package/tradelayer.js/tests/sensitiveConsoleOutput.txt +267 -0
  168. package/tradelayer.js/tests/tallyTest.js +40 -0
  169. package/tradelayer.js/tests/testBuybacks.js +46 -0
  170. package/tradelayer.js/tests/testCodeHash.js +49 -0
  171. package/tradelayer.js/tests/testConsensusHash.js +91 -0
  172. package/tradelayer.js/tests/testDecode.js +30 -0
  173. package/tradelayer.js/tests/testEncodingLengths.js +129 -0
  174. package/tradelayer.js/tests/testGetTx +32 -0
  175. package/tradelayer.js/tests/testGetTx.js +32 -0
  176. package/tradelayer.js/tests/testHexHash.js +32 -0
  177. package/tradelayer.js/tests/testIndexHash.js +35 -0
  178. package/tradelayer.js/tests/testInitContracts.js +38 -0
  179. package/tradelayer.js/tests/testMaxConsensus.js +12 -0
  180. package/tradelayer.js/tests/testMaxSynth.js +44 -0
  181. package/tradelayer.js/tests/testMint.js +21 -0
  182. package/tradelayer.js/tests/testNetwork.js +33 -0
  183. package/tradelayer.js/tests/testOrderbookLoad.js +62 -0
  184. package/tradelayer.js/tests/testRebates.js +32 -0
  185. package/tradelayer.js/tests/testRedeem.js +22 -0
  186. package/tradelayer.js/tests/testTokenTrade.js +39 -0
  187. package/tradelayer.js/tests/testTxBuild.js +42 -0
  188. package/tradelayer.js/tests/testUTXOTrade.js +27 -0
  189. package/tradelayer.js/tests/tokenTradeHistory.js +27 -0
  190. package/tradelayer.js/tests/tradeFutures.js +40 -0
  191. package/tradelayer.js/tests/tradeHistoryExample.js +35 -0
  192. package/tradelayer.js/tests/tradeHistoryLoad.js +15 -0
  193. package/tradelayer.js/tests/txScanTest.js +134 -0
  194. package/tradelayer.js/tests/validateTest.js +136 -0
  195. package/tradelayer.js/tests/vestingTest.js +37 -0
  196. package/tradelayer.js/utils/activateMainnet.js +59 -0
  197. package/tradelayer.js/utils/activateMainnetDoge.js +63 -0
  198. package/tradelayer.js/utils/autocompactdb.js +23 -0
  199. package/tradelayer.js/utils/base64toHex.js +32 -0
  200. package/tradelayer.js/utils/broadcastDoge.js +38 -0
  201. package/tradelayer.js/utils/calcRedeem.js +19 -0
  202. package/tradelayer.js/utils/checkNetwork.js +27 -0
  203. package/tradelayer.js/utils/createAddress.js +48 -0
  204. package/tradelayer.js/utils/createAttestation.js +133 -0
  205. package/tradelayer.js/utils/createContract.js +118 -0
  206. package/tradelayer.js/utils/createOracle.js +94 -0
  207. package/tradelayer.js/utils/createwallet.js +20 -0
  208. package/tradelayer.js/utils/crossFuturesTrades.js +57 -0
  209. package/tradelayer.js/utils/crossTokenTrades.js +62 -0
  210. package/tradelayer.js/utils/dumpPriv.js +29 -0
  211. package/tradelayer.js/utils/generateChannel.js +34 -0
  212. package/tradelayer.js/utils/getInfo.js +21 -0
  213. package/tradelayer.js/utils/hardWipe.js +20 -0
  214. package/tradelayer.js/utils/hexTo64.js +16 -0
  215. package/tradelayer.js/utils/importAddress.js +28 -0
  216. package/tradelayer.js/utils/importpriv.js +20 -0
  217. package/tradelayer.js/utils/issueOracleContract.js +67 -0
  218. package/tradelayer.js/utils/issueTokens.js +41 -0
  219. package/tradelayer.js/utils/listunspent.js +66 -0
  220. package/tradelayer.js/utils/litecoinClient.js +30 -0
  221. package/tradelayer.js/utils/loadwallet.js +20 -0
  222. package/tradelayer.js/utils/publishOracle.js +113 -0
  223. package/tradelayer.js/utils/sendActivation.js +21 -0
  224. package/tradelayer.js/utils/sendChannelContractTrade.js +34 -0
  225. package/tradelayer.js/utils/sendChannelTokenTrade.js +34 -0
  226. package/tradelayer.js/utils/sendCommit.js +24 -0
  227. package/tradelayer.js/utils/sendDoge.js +62 -0
  228. package/tradelayer.js/utils/sendDogeMain.js +67 -0
  229. package/tradelayer.js/utils/sendDogeTx.js +46 -0
  230. package/tradelayer.js/utils/sendLTC.js +63 -0
  231. package/tradelayer.js/utils/sendMainnet.js +62 -0
  232. package/tradelayer.js/utils/sendTransfer.js +19 -0
  233. package/tradelayer.js/utils/sendVestTest.js +88 -0
  234. package/tradelayer.js/utils/sendWithdrawal.js +26 -0
  235. package/tradelayer.js/utils/simpleStart.js +8 -0
  236. package/tradelayer.js/utils/startStop.js +27 -0
  237. package/tradelayer.js/utils/structuredTrades.js +136 -0
  238. package/tradelayer.js/utils/verifySignature.js +90 -0
  239. package/tradelayer.js/utils/verifyWitnessAndScriptPubkey.js +41 -0
  240. package/tradelayer.js/utils/walletCache.js +172 -0
  241. package/tradelayer.js/utils/walletContractInterface.js +48 -0
  242. package/tradelayer.js/utils/walletFetchTxs.js +66 -0
  243. package/tradelayer.js/utils/walletUtils.js +97 -0
  244. package/tradelayer.js/utils/wipeDB.js +55 -0
  245. package/tradelayer.js/utils/wipeDBNotTx.js +50 -0
  246. package/txEncoder.js +529 -0
  247. package/utility.js +28 -0
  248. package/verifymessage.js +38 -0
  249. package/ws-transport.js +311 -0
package/mmEx.js ADDED
@@ -0,0 +1,356 @@
1
+ /**
2
+ * mmEx_dualLayer.js — fast BBO trackers + slosh (≤5 bps), hedge on fills
3
+ *
4
+ * Requirements satisfied:
5
+ * - 2 tracking orders per side that closely follow Binance bid/ask (fast)
6
+ * - A "slosh" set of deeper passive orders kept within 5 bps; stay put unless trespass/out-of-band
7
+ * - Hedge on any detected fill (order disappears without our cancel)
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ const WebSocket = require('ws');
15
+ const ccxt = require('ccxt');
16
+ const { apiKey, secret } = require('./keys.js');
17
+ const ApiWrapper = require('./algoAPI.js');
18
+
19
+ // ===== Config =====
20
+ const LOG_PATH = path.join(process.env.HOME || process.env.USERPROFILE || '.', 'Downloads', 'mmEx.dual.log');
21
+
22
+ const TL_WS_HOST = 'ws://172.26.37.103';
23
+ const TL_WS_PORT = 3001;
24
+ const TL_NETWORK = 'LTCTEST';
25
+ const TL_ADDR = 'tltc1qvlwcnwlhnja7wlj685ptwxej75mms9nyv7vuy8';
26
+
27
+ const BASE_ID = 0; // LTC
28
+ const QUOTE_ID = 5; // USDTt
29
+ const SYMBOL = 'LTC/USDT';
30
+
31
+ // Tracking layer (fast)
32
+ const TRACK_LEVELS_PER_SIDE = 2;
33
+ const TRACK_EDGE_BPS = 1.0; // first level distance from BBO
34
+ const TRACK_STEP_BPS = 1.0; // gap between tracking levels
35
+ const TRACK_SIZE = 0.10;
36
+ const TRACK_DEBOUNCE_MS = 150; // per side
37
+
38
+ // Slosh layer (slow)
39
+ const SLOSH_LEVELS_PER_SIDE = 3; // number of slosh levels per side
40
+ const SLOSH_MAX_BPS = 5.0; // must remain within 5 bps to stay
41
+ const SLOSH_START_BPS = 2.0; // first slosh level distance from BBO
42
+ const SLOSH_STEP_BPS = 1.5; // between levels, not to exceed 5 bps
43
+ const SLOSH_SIZE = 0.15;
44
+ const SLOSH_DEBOUNCE_MS = 1200; // slower refresh
45
+
46
+ // Safety / plumbing
47
+ const CANCEL_TIMEOUT_MS = 1500;
48
+ const PLACE_TIMEOUT_MS = 1500;
49
+ const EXCH_SPREAD_MIN = 0.005; // don't quote if exchange spread too tight
50
+ const EXCH_SPREAD_MAX = 1.00; // ignore if absurd
51
+ const HEDGE_SLIPPAGE_F = 0.25; // market hedge slippage factor vs last BBO
52
+
53
+ // ===== Logging =====
54
+ const logStream = fs.createWriteStream(LOG_PATH, { flags: 'a' });
55
+ function log(...a) {
56
+ const line = `[${new Date().toISOString()}] ${a.map(String).join(' ')}\n`;
57
+ if (!logStream.destroyed) logStream.write(line);
58
+ console.log(...a);
59
+ }
60
+
61
+ // ===== External deps =====
62
+ const binance = new ccxt.binance({ apiKey, secret, enableRateLimit: true });
63
+ const api = new ApiWrapper(
64
+ TL_WS_HOST, TL_WS_PORT,
65
+ true, // debug
66
+ true, // autoConnect
67
+ { address: TL_ADDR, otherAddrs: [] },
68
+ TL_NETWORK
69
+ );
70
+
71
+ // ===== State =====
72
+ let bestBid = null, bestAsk = null;
73
+
74
+ const layer = {
75
+ TRACK: { BUY: [], SELL: [] }, // items: {uuid, px, sz}
76
+ SLOSH: { BUY: [], SELL: [] }
77
+ };
78
+
79
+ const lastTouch = {
80
+ TRACK: { BUY: 0, SELL: 0 },
81
+ SLOSH: { BUY: 0, SELL: 0 }
82
+ };
83
+
84
+ const ours = new Set(); // all open order UUIDs we believe are live
85
+ const oursMeta = new Map(); // uuid -> {side, layer:'TRACK'|'SLOSH', px, sz}
86
+
87
+ function now() { return Date.now(); }
88
+ function bps(x) { return x / 10000; }
89
+ function tooSoon(kind, side, ms) { return now() - lastTouch[kind][side] < ms; }
90
+ function touch(kind, side) { lastTouch[kind][side] = now(); }
91
+
92
+ function toTLBuy(price, amount) {
93
+ return { type: 'SPOT', action: 'BUY', props: { id_for_sale: QUOTE_ID, id_desired: BASE_ID, price, amount, transfer: false } };
94
+ }
95
+ function toTLSell(price, amount) {
96
+ return { type: 'SPOT', action: 'SELL', props: { id_for_sale: BASE_ID, id_desired: QUOTE_ID, price, amount, transfer: false } };
97
+ }
98
+
99
+ async function withTimeout(p, ms, tag) {
100
+ let t; const killer = new Promise((_, rej) => t = setTimeout(() => rej(new Error(`${tag} timeout ${ms}ms`)), ms));
101
+ try { return await Promise.race([p, killer]); }
102
+ finally { clearTimeout(t); }
103
+ }
104
+
105
+ // ===== Binance WS (depth) =====
106
+ const ws = new WebSocket('wss://stream.binance.com:9443/ws');
107
+ ws.on('open', () => {
108
+ ws.send(JSON.stringify({ method: 'SUBSCRIBE', params: ['ltcusdt@depth'], id: 1 }));
109
+ log('Subscribed Binance: ltcusdt@depth');
110
+ });
111
+ ws.on('message', (raw) => {
112
+ try {
113
+ const d = JSON.parse(raw);
114
+ const b = Number(d?.b?.[0]?.[0]);
115
+ const a = Number(d?.a?.[0]?.[0]);
116
+ if (Number.isFinite(b) && Number.isFinite(a) && a > b) {
117
+ bestBid = b; bestAsk = a;
118
+ }
119
+ } catch {}
120
+ });
121
+ ws.on('error', (e) => log('WS error', e.message || e));
122
+
123
+ // ===== TL ops =====
124
+ async function place(kind, side, px, sz) {
125
+ const det = side === 'BUY' ? toTLBuy(px, sz) : toTLSell(px, sz);
126
+ const uuid = await withTimeout(api.sendOrder(det), PLACE_TIMEOUT_MS, 'place');
127
+ const id = uuid?.orderUuid || uuid;
128
+ layer[kind][side].push({ uuid: id, px, sz });
129
+ ours.add(id);
130
+ oursMeta.set(id, { side, layer: kind, px, sz });
131
+ log('PLACED', kind, side, px.toFixed(6), 'uuid=', id);
132
+ }
133
+
134
+ async function cancel(kind, side, idx, reason) {
135
+ const item = layer[kind][side][idx];
136
+ if (!item) return;
137
+ const id = item.uuid;
138
+ try {
139
+ await withTimeout(api.cancelOrder(id), CANCEL_TIMEOUT_MS, 'cancel');
140
+ log('CANCELED', kind, side, item.px.toFixed(6), 'uuid=', id, 'reason=', reason);
141
+ } catch (e) {
142
+ log('CANCEL FAIL', kind, side, id, e.message || e);
143
+ } finally {
144
+ layer[kind][side].splice(idx, 1);
145
+ ours.delete(id);
146
+ oursMeta.delete(id);
147
+ }
148
+ }
149
+
150
+ function genTargets_TRACK(bid, ask) {
151
+ const bids = [], asks = [];
152
+ for (let i = 0; i < TRACK_LEVELS_PER_SIDE; i++) {
153
+ bids.push({ px: bid * (1 - bps(TRACK_EDGE_BPS + i * TRACK_STEP_BPS)), sz: TRACK_SIZE });
154
+ asks.push({ px: ask * (1 + bps(TRACK_EDGE_BPS + i * TRACK_STEP_BPS)), sz: TRACK_SIZE });
155
+ }
156
+ return { bids, asks };
157
+ }
158
+
159
+ function genTargets_SLOSH(bid, ask) {
160
+ const bids = [], asks = [];
161
+ for (let i = 0; i < SLOSH_LEVELS_PER_SIDE; i++) {
162
+ const dist = Math.min(SLOSH_START_BPS + i * SLOSH_STEP_BPS, SLOSH_MAX_BPS);
163
+ bids.push({ px: bid * (1 - bps(dist)), sz: SLOSH_SIZE, dist });
164
+ asks.push({ px: ask * (1 + bps(dist)), sz: SLOSH_SIZE, dist });
165
+ }
166
+ return { bids, asks };
167
+ }
168
+
169
+ // Keep order if: still within SLOSH_MAX_BPS of current BBO and not trespassing
170
+ function sloshStillValid(side, px, bid, ask) {
171
+ if (side === 'BUY') {
172
+ const relBps = Math.abs((bid - px) / bid) * 10000;
173
+ return px <= bid && relBps <= SLOSH_MAX_BPS;
174
+ } else {
175
+ const relBps = Math.abs((px - ask) / ask) * 10000;
176
+ return px >= ask && relBps <= SLOSH_MAX_BPS;
177
+ }
178
+ }
179
+
180
+ function pickMissing(existingPx, targets, tolBps) {
181
+ const out = [];
182
+ for (const t of targets) {
183
+ const near = existingPx.some(px => Math.abs(px - t.px) <= (t.px * bps(tolBps)));
184
+ if (!near) out.push(t);
185
+ }
186
+ return out;
187
+ }
188
+
189
+ // ===== Hedging on fills =====
190
+ // We detect fills by diffs: If a UUID disappears from server-open-orders and we did NOT cancel it, treat as fill
191
+ async function hedgeOnFill(side, px, sz) {
192
+ try {
193
+ // simple market hedge opposite to TL side
194
+ if (!Number.isFinite(bestBid) || !Number.isFinite(bestAsk)) return;
195
+ const ref = side === 'BUY' ? bestAsk : bestBid;
196
+ const price = side === 'BUY'
197
+ ? ref * (1 - bps(HEDGE_SLIPPAGE_F)) // we sold on TL, buy on Binance a bit below ask if allowed
198
+ : ref * (1 + bps(HEDGE_SLIPPAGE_F)); // we bought on TL, sell on Binance a bit above bid if allowed
199
+
200
+ const hedgeSide = side === 'BUY' ? 'buy' : 'sell'; // reverse? we *bought* on TL -> hedge by *sell*; adjust:
201
+ const takerSide = (side === 'BUY') ? 'sell' : 'buy';
202
+ await binance.createOrder(SYMBOL, 'market', takerSide, sz, undefined);
203
+ log('HEDGE', takerSide, sz, SYMBOL, 'ok (fill detected at TL)');
204
+ } catch (e) {
205
+ log('HEDGE FAIL', e.message || e);
206
+ }
207
+ }
208
+
209
+ // Hook: wire to your ApiWrapper’s stream of account updates / orders list
210
+ // Expect a payload like: { event: 'PLACED_ORDERS', openedOrders: [...uuids...] }
211
+ api.onMessage?.((msg) => {
212
+ try {
213
+ if (!msg) return;
214
+ // normalize possible shapes
215
+ const ev = msg.event || msg.type || '';
216
+ if (String(ev).toUpperCase().includes('PLACED') && Array.isArray(msg.openedOrders)) {
217
+ const openNow = new Set((msg.openedOrders || []).map(o => o.uuid || o.orderUuid || o));
218
+ for (const id of Array.from(ours)) {
219
+ if (!openNow.has(id)) {
220
+ // if it disappeared and we didn't remove it locally => filled (or canceled by match)
221
+ const meta = oursMeta.get(id);
222
+ if (meta) {
223
+ log('FILL-DETECTED', id, meta.side, meta.layer, meta.px);
224
+ hedgeOnFill(meta.side, meta.px, meta.sz).catch(()=>{});
225
+ // clean local state if still present in a layer
226
+ for (const KIND of ['TRACK','SLOSH']) {
227
+ for (const SIDE of ['BUY','SELL']) {
228
+ const idx = layer[KIND][SIDE].findIndex(x => x.uuid === id);
229
+ if (idx >= 0) layer[KIND][SIDE].splice(idx, 1);
230
+ }
231
+ }
232
+ ours.delete(id);
233
+ oursMeta.delete(id);
234
+ }
235
+ }
236
+ }
237
+ }
238
+ } catch {}
239
+ });
240
+
241
+ // ===== Reconcilers =====
242
+ async function reconcileTRACK(bid, ask) {
243
+ // debounce per side
244
+ for (const side of ['BUY','SELL']) {
245
+ if (tooSoon('TRACK', side, TRACK_DEBOUNCE_MS)) continue;
246
+ touch('TRACK', side);
247
+
248
+ const targets = genTargets_TRACK(bid, ask);
249
+ const tgt = side === 'BUY' ? targets.bids : targets.asks;
250
+ const existing = layer.TRACK[side];
251
+
252
+ // cancel if too many or trespass BBO (shouldn’t happen, but guard)
253
+ for (let i = existing.length - 1; i >= 0; i--) {
254
+ const { px } = existing[i];
255
+ const trespass = (side === 'BUY') ? (px > bid) : (px < ask);
256
+ const tooMany = existing.length > TRACK_LEVELS_PER_SIDE;
257
+ if (trespass || tooMany) {
258
+ await cancel('TRACK', side, i, trespass ? 'trespass' : 'excess');
259
+ }
260
+ }
261
+
262
+ // place missing near BBO (tolerance half a step)
263
+ const miss = pickMissing(existing.map(e => e.px), tgt, TRACK_STEP_BPS * 0.6);
264
+ for (const m of miss.slice(0, Math.max(0, TRACK_LEVELS_PER_SIDE - existing.length))) {
265
+ await place('TRACK', side, m.px, m.sz);
266
+ }
267
+ }
268
+ }
269
+
270
+ async function reconcileSLOSH(bid, ask) {
271
+ for (const side of ['BUY','SELL']) {
272
+ if (tooSoon('SLOSH', side, SLOSH_DEBOUNCE_MS)) continue;
273
+ touch('SLOSH', side);
274
+
275
+ const targets = genTargets_SLOSH(bid, ask);
276
+ const tgt = side === 'BUY' ? targets.bids : targets.asks;
277
+ const existing = layer.SLOSH[side];
278
+
279
+ // prune invalid: outside 5 bps window or trespass
280
+ for (let i = existing.length - 1; i >= 0; i--) {
281
+ const { px } = existing[i];
282
+ if (!sloshStillValid(side, px, bid, ask)) {
283
+ await cancel('SLOSH', side, i, 'out-of-band');
284
+ }
285
+ }
286
+
287
+ // place up to desired count; tolerance slightly wider than track
288
+ const miss = pickMissing(existing.map(e => e.px), tgt, Math.min(SLOSH_MAX_BPS, SLOSH_STEP_BPS));
289
+ for (const m of miss.slice(0, Math.max(0, SLOSH_LEVELS_PER_SIDE - layer.SLOSH[side].length))) {
290
+ // clamp distances to SLOSH_MAX_BPS
291
+ const bbo = side === 'BUY' ? bid : ask;
292
+ const rel = Math.abs((m.px - bbo) / bbo) * 10000;
293
+ if (rel <= SLOSH_MAX_BPS) await place('SLOSH', side, m.px, m.sz);
294
+ }
295
+ }
296
+ }
297
+
298
+ // ===== Main tick =====
299
+ async function tick() {
300
+ if (!Number.isFinite(bestBid) || !Number.isFinite(bestAsk)) return;
301
+ const spread = bestAsk - bestBid;
302
+ if (spread < EXCH_SPREAD_MIN || spread > EXCH_SPREAD_MAX) return;
303
+
304
+ await reconcileTRACK(bestBid, bestAsk);
305
+ await reconcileSLOSH(bestBid, bestAsk);
306
+ }
307
+
308
+ // ===== Graceful shutdown =====
309
+ async function shutdown() {
310
+ log('Shutdown: cancel all…');
311
+ for (const KIND of ['TRACK','SLOSH']) {
312
+ for (const SIDE of ['BUY','SELL']) {
313
+ for (let i = layer[KIND][SIDE].length - 1; i >= 0; i--) {
314
+ try { await cancel(KIND, SIDE, i, 'shutdown'); } catch {}
315
+ }
316
+ }
317
+ }
318
+ process.exit(0);
319
+ }
320
+ process.on('SIGINT', shutdown);
321
+ process.on('SIGTERM', shutdown);
322
+
323
+ // ===== Boot =====
324
+ (async () => {
325
+ log('mmEx_dualLayer starting…');
326
+ await new Promise(r => setTimeout(r, 1500));
327
+ setInterval(() => { tick().catch(e => log('tick err', e.message || e)); }, 120);
328
+
329
+ // Optional: periodic reconcile of fills if your wrapper has a getter
330
+ // If ApiWrapper exposes api.getMyOpenOrders(), uncomment this poller:
331
+ /*
332
+ setInterval(async () => {
333
+ try {
334
+ const list = await api.getMyOpenOrders();
335
+ const openNow = new Set((list || []).map(o => o.uuid || o.orderUuid || o));
336
+ for (const id of Array.from(ours)) {
337
+ if (!openNow.has(id)) {
338
+ const meta = oursMeta.get(id);
339
+ if (meta) {
340
+ log('FILL-DETECTED(POLL)', id, meta.side, meta.layer, meta.px);
341
+ hedgeOnFill(meta.side, meta.px, meta.sz).catch(()=>{});
342
+ ours.delete(id);
343
+ oursMeta.delete(id);
344
+ for (const KIND of ['TRACK','SLOSH']) {
345
+ for (const SIDE of ['BUY','SELL']) {
346
+ const idx = layer[KIND][SIDE].findIndex(x => x.uuid === id);
347
+ if (idx >= 0) layer[KIND][SIDE].splice(idx, 1);
348
+ }
349
+ }
350
+ }
351
+ }
352
+ }
353
+ } catch {}
354
+ }, 800);
355
+ */
356
+ })();
package/networks.js ADDED
@@ -0,0 +1,51 @@
1
+ const BTC = {
2
+ messagePrefix: '\x18Bitcoin Signed Message:\n',
3
+ bech32: 'bc',
4
+ bip32: {
5
+ public: 0x0488b21e,
6
+ private: 0x0488ade4,
7
+ },
8
+ pubKeyHash: 0x00,
9
+ scriptHash: 0x05,
10
+ wif: 0x80,
11
+ };
12
+
13
+ const BTCTEST = {
14
+ messagePrefix: '\x18Bitcoin Testnet Signed Message:\n',
15
+ bech32: 'tb',
16
+ bip32: {
17
+ public: 0x043587cf,
18
+ private: 0x04358394,
19
+ },
20
+ pubKeyHash: 0x6f,
21
+ scriptHash: 0xc4,
22
+ wif: 0xef,
23
+ };
24
+
25
+ const LTC = {
26
+ messagePrefix: '\x19Litecoin Signed Message:\n',
27
+ bech32: 'ltc',
28
+ bip32: {
29
+ public: 0x019da462,
30
+ private: 0x019d9cfe,
31
+ },
32
+ pubKeyHash: 0x30,
33
+ scriptHash: 0x32,
34
+ wif: 0xb0,
35
+ };
36
+
37
+ const LTCTEST = {
38
+ messagePrefix: '\x19Litecoin Testnet Signed Message:\n',
39
+ bech32: 'tltc',
40
+ bip32: {
41
+ public: 0x0436f6e1,
42
+ private: 0x0436ef7d,
43
+ },
44
+ pubKeyHash: 0x6f,
45
+ scriptHash: 0x3a,
46
+ wif: 0xef,
47
+ };
48
+
49
+ const networks = { BTC, LTC, LTCTEST, BTCTEST };
50
+
51
+ module.exports = networks
package/orderbook.js ADDED
@@ -0,0 +1,200 @@
1
+ const SellSwapper = require('./seller.js')
2
+ const BuySwapper = require('./buyer.js')
3
+ const BigNumber = require('bignumber.js')
4
+
5
+ class OrderbookSession {
6
+ constructor(socket, myInfo, client,test) {
7
+ console.log('initializing orderbook '+JSON.stringify(myInfo))
8
+ this.socket = socket;
9
+ this.myInfo = myInfo;
10
+ this.client = client;
11
+ this.test = test
12
+
13
+ // Start the session and listen for various events
14
+ this.startSession();
15
+ }
16
+
17
+ setInfo(myInfo){
18
+ this.myInfo=myInfo
19
+ }
20
+
21
+ // Start the session and manage connection lifecycle
22
+ startSession() {
23
+ this.socket.on('connection', () => {
24
+ console.log('Connected to the orderbook server.');
25
+ this.subscribeToOrderbook();
26
+ });
27
+
28
+ this.socket.on('disconnect', () => {
29
+ console.log('Disconnected from the orderbook server.');
30
+ // Reconnection logic could be added here if necessary
31
+ });
32
+
33
+ this.handleOrderMatches();
34
+ this.handleNewOrders();
35
+ this.handleOrderUpdates();
36
+ this.handleClosedOrders();
37
+ }
38
+
39
+ // Subscribe to orderbook updates after connection
40
+ subscribeToOrderbook() {
41
+ // Subscribe to specific assets or full orderbook
42
+ this.socket.emit('subscribe', { event: 'update-orderbook', assets: ['LTC', 'BTC'] });
43
+ console.log('Subscribed to orderbook data for assets: LTC, BTC.');
44
+
45
+ // Listening for general orderbook updates
46
+ this.socket.on('update-orderbook', (data) => {
47
+ console.log('Orderbook Updated:', data);
48
+ // You can update your local orderbook or UI here
49
+ });
50
+ }
51
+
52
+ // Handle new orders
53
+ handleNewOrders() {
54
+ this.socket.on('new-order', (newOrderData) => {
55
+ console.log('socket in new order '+JSON.stringify(this.socket)+' '+this.socket)
56
+ console.log('New Order:', newOrderData);
57
+ // You can update the UI or alert the user about new orders
58
+ });
59
+
60
+ this.socket.on('many-orders', (bulkOrdersData) => {
61
+ console.log('Many Orders Received:', bulkOrdersData);
62
+ // Handle bulk order updates (e.g., refreshing the full orderbook)
63
+ });
64
+ }
65
+
66
+ // Handle updates to existing orders in the orderbook
67
+ handleOrderUpdates() {
68
+ this.socket.on('update-orderbook', (updateData) => {
69
+ console.log('Orderbook Update:', updateData);
70
+ // Handle any updates to the orderbook here
71
+ });
72
+ }
73
+
74
+ // Handle order closing or cancellations
75
+ handleClosedOrders() {
76
+ this.socket.on('close-order', (orderUUID) => {
77
+ console.log(`Order ${orderUUID} closed or canceled.`);
78
+ // Remove the order from the UI or local state
79
+ });
80
+ }
81
+
82
+ // Handle matched orders and initiate trade swaps
83
+ handleOrderMatches() {
84
+ this.socket.on('new-channel', async (swapConfig) => {
85
+ const tradeInfo = swapConfig?.tradeInfo;
86
+ console.log('inside handleOrderMatches on algo '+JSON.stringify(swapConfig))
87
+ if (!tradeInfo?.buyer || !tradeInfo?.seller) {
88
+ return;
89
+ }
90
+
91
+ //console.log('swap config '+JSON.stringify(swapConfig))
92
+ if(!swapConfig.tradeInfo.buyer||!swapConfig.tradeInfo.seller){return}
93
+ try {
94
+ const { tradeInfo, isBuyer } = swapConfig; // Extract the relevant trade info and buyer/seller flag
95
+ const { buyer, seller, props, type } = tradeInfo; // Get buyer/seller info and trade properties
96
+
97
+ console.log('new channel match '+JSON.stringify(swapConfig)+' trade info'+JSON.stringify(tradeInfo))
98
+ // Make sure the buyer/seller addresses are properly matched
99
+ console.log('my address'+this.myInfo.keypair.address, +' buyer.address '+buyer.keypair.address+' seller.address '+seller.keypair.address)
100
+ if(!this.myInfo.keypair.address){
101
+ const address = await this.getUTXOBalances()
102
+ if(!address||!this.myInfo.keypair.address){console.log('houston we have a problem')}
103
+ }
104
+ if (this.myInfo.keypair.address === buyer.keypair.address){
105
+ console.log('Initiating Buy Swap...');
106
+ await this.initiateBuySwap(type, tradeInfo, buyer, seller);
107
+ } else if (this.myInfo.keypair.address === seller.keypair.address){
108
+ console.log('Initiating Sell Swap...');
109
+ await this.initiateSellSwap(type, tradeInfo, buyer, seller);
110
+ } else {
111
+ console.log('Address mismatch, cannot proceed with swap.');
112
+ }
113
+ } catch (error) {
114
+ console.error('Error handling matched order:', error);
115
+ }
116
+ });
117
+ }
118
+
119
+ // Initialize buy swap
120
+ async initiateBuySwap(typeTrade, tradeInfo, buyerInfo, sellerInfo) {
121
+ const key = [tradeInfo.buyer?.uuid, tradeInfo.seller?.uuid].join('-');
122
+ try {
123
+ const buySwapper = new BuySwapper(typeTrade, tradeInfo, buyerInfo, sellerInfo, this.client, this.socket,this.test,key);
124
+ const res = await buySwapper.onReady();
125
+ if (res.error) {
126
+ console.error(`Buy Swap Failed: ${res.error}`);
127
+ } else {
128
+ console.log(`Buy Swap Complete: ${res.data}`);
129
+ }
130
+ } catch (error) {
131
+ console.error('Error initiating Buy Swap:', error);
132
+ }
133
+ }
134
+
135
+ // Initialize sell swap
136
+ async initiateSellSwap(typeTrade, tradeInfo, buyerInfo, sellerInfo) {
137
+ const key = [tradeInfo.buyer?.uuid, tradeInfo.seller?.uuid].join('-');
138
+
139
+ try {
140
+ const sellSwapper = new SellSwapper(typeTrade, tradeInfo, sellerInfo, buyerInfo, this.client, this.socket,this.test,key);
141
+ const res = await sellSwapper.onReady();
142
+ if (res.error) {
143
+ console.error(`Sell Swap Failed: ${res.error}`);
144
+ } else {
145
+ console.log(`Sell Swap Complete: ${res.data}`);
146
+ }
147
+ } catch (error) {
148
+ console.error('Error initiating Sell Swap:', error);
149
+ }
150
+ }
151
+
152
+ async getUTXOBalances(address) {
153
+ try {
154
+ const utxos = await this.listUnspent(); // Fetch sunspent transactions
155
+ console.log('utxos returned 2nd pass in orderbook '+JSON.stringify(utxos))
156
+ let totalBalance = new BigNumber(0);
157
+
158
+ for (const utxo of utxos) {
159
+ console.log('scanning utxos '+utxo.address+' '+utxo.amount)
160
+ if (utxo.address === address){
161
+ totalBalance += utxo.amount; // Sum balances for the specific address
162
+ } else if (!this.myInfo.keypair.address){
163
+ this.myInfo.keypair.address = utxo.address;
164
+ this.myInfo.keypair.pubkey = await this.getPubKeyFromAddress(utxo.address); // Get pubkey for the new address
165
+ console.log('logging pubkey ' +this.myInfo.keypair.pubkey+' '+this.myInfo.keypair.address)
166
+ totalBalance += utxo.amount;
167
+ } else if (address === '' && this.myInfo.keypair.address){
168
+ const pubkey = await this.getPubKeyFromAddress(utxo.address);
169
+ this.myInfo.otherAddrs.push({ address: utxo.address, pubkey: pubkey });
170
+ totalBalance += utxo.amount;
171
+ }
172
+ }
173
+
174
+ console.log(`Total UTXO balance for address ${this.myInfo.keypair.address}:`, totalBalance);
175
+
176
+ return this.myInfo.keypair.address
177
+ } catch (error) {
178
+ console.error('Error fetching UTXO balances:', error);
179
+ }
180
+ }
181
+
182
+ listUnspent(...params) {
183
+ return util.promisify(this.client.cmd.bind(this.client, 'listunspent'))(...params);
184
+ }
185
+
186
+ async getPubKeyFromAddress(address) {
187
+ try {
188
+ const addressInfo = await this.getAddressInfo(address);
189
+ if (addressInfo && addressInfo.pubkey) {
190
+ return addressInfo.pubkey;
191
+ } else {
192
+ throw new Error('Public key not found for address');
193
+ }
194
+ } catch (error) {
195
+ console.error('Error fetching pubkey:', error);
196
+ }
197
+ }
198
+ }
199
+
200
+ module.exports = OrderbookSession
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@tradelayerprotocol/tradelayer",
3
+ "version": "1.9.1",
4
+ "description": "NPM package for interacting with TradeLayer orderbook and building Litecoin/Token/Futures transactions.",
5
+ "main": "index.js",
6
+ "dependencies": {
7
+ "axios": "^1.7.7",
8
+ "bigint-base-converter": "^0.1.3",
9
+ "bignumber.js": "^9.1.2",
10
+ "bip32": "^5.0.0",
11
+ "bip39": "^3.1.0",
12
+ "bitcoin": "^3.0.3",
13
+ "bitcoinjs-lib": "^6.1.6",
14
+ "bitcore-lib-ltc": "^10.0.21",
15
+ "ccxt": "^4.4.77",
16
+ "dotenv": "^16.4.5",
17
+ "ecpair": "^3.0.0",
18
+ "isomorphic-ws": "^5.0.0",
19
+ "litecoin": "^2.0.5",
20
+ "socket.io-client": "^4.7.5",
21
+ "tiny-secp256k1": "^2.2.4",
22
+ "tradelayer": "^1.5.2",
23
+ "ws": "^8.18.0"
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/patrickdugan/tlnpm"
28
+ },
29
+ "scripts": {
30
+ "start": "node algoAPI.js"
31
+ },
32
+ "author": "Your Name",
33
+ "license": "MIT"
34
+ }
@@ -0,0 +1,36 @@
1
+ // perTradeQueue.js
2
+ 'use strict';
3
+
4
+ /**
5
+ * Run async functions sequentially *per key*.
6
+ * Calls for different keys can run in parallel.
7
+ */
8
+ const pending = new Map();
9
+
10
+ /**
11
+ * @param {string} key e.g. `${buyerUuid}-${sellerUuid}`
12
+ * @param {() => Promise<any>} fn async work to run
13
+ */
14
+ function runForKey(key, fn) {
15
+ if (!key) {
16
+ // no key → just run without queuing
17
+ return Promise.resolve().then(fn);
18
+ }
19
+
20
+ const prev = pending.get(key) || Promise.resolve();
21
+
22
+ const next = prev
23
+ .catch(() => {}) // swallow errors from previous tasks
24
+ .then(() => fn())
25
+ .finally(() => {
26
+ // clear if this is still the tail
27
+ if (pending.get(key) === next) pending.delete(key);
28
+ });
29
+
30
+ pending.set(key, next);
31
+ return next;
32
+ }
33
+
34
+ module.exports = {
35
+ runForKey,
36
+ };