@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/buyer.js ADDED
@@ -0,0 +1,622 @@
1
+ const litecore = require('bitcore-lib-ltc');
2
+ const Encode = require('./tradelayer.js/src/txEncoder.js'); // Use encoder.js for payload generation
3
+ const BigNumber = require('bignumber.js');
4
+ const { buildLitecoinTransaction, buildTokenTradeTransaction, buildFuturesTransaction, buildSignAndBroadcastCommitTx, signPsbtRawTx } = require('./litecoreTxBuilder');
5
+ const WalletListener = require('./tradelayer.js/src/walletInterface.js'); // Import WalletListener to use tl_getChannelColumn
6
+ const util = require('util');
7
+ const {Psbt}= require('bitcoinjs-lib')
8
+
9
+ class BuySwapper {
10
+ constructor(
11
+ typeTrade, // New parameter for trade type ('BUY')
12
+ tradeInfo, // Trade information
13
+ buyerInfo, // Buyer information
14
+ sellerInfo, // Seller information
15
+ client, // Litecoin client or another client service
16
+ socket, // Socket for communication
17
+ test,
18
+ tradeUUID
19
+ ) {
20
+ this.typeTrade = typeTrade; // 'BUY' or 'SELL'
21
+ this.tradeInfo = tradeInfo; // Trade information (e.g., amount, price, etc.)
22
+ this.myInfo = buyerInfo; // Information about the buyer
23
+ this.cpInfo = sellerInfo; // Information about the seller
24
+ this.socket = socket; // Socket connection for real-time events
25
+ this.client = client; // Client for making RPC calls
26
+ this.test= test
27
+ this.multySigChannelData = null; // Initialize multisig channel data
28
+ this.tradeUUID = tradeUUID
29
+ // Promisify methods for the given client
30
+ this.getRawTransactionAsync = util.promisify(this.client.getRawTransaction.bind(this.client));
31
+ this.getBlockDataAsync = util.promisify(this.client.getBlock.bind(this.client));
32
+ this.createRawTransactionAsync = util.promisify(this.client.createRawTransaction.bind(this.client));
33
+ this.listUnspentAsync = util.promisify(this.client.cmd.bind(this.client, 'listunspent'));
34
+ this.decoderawtransactionAsync = util.promisify(this.client.cmd.bind(this.client, 'decoderawtransaction'));
35
+ this.dumpprivkeyAsync = util.promisify(this.client.cmd.bind(this.client, 'dumpprivkey'));
36
+ this.sendrawtransactionAsync = util.promisify(this.client.cmd.bind(this.client, 'sendrawtransaction'));
37
+ this.validateAddress = util.promisify(this.client.cmd.bind(this.client, 'validateaddress'));
38
+ this.getBlockCountAsync = util.promisify(this.client.cmd.bind(this.client, 'getblockcount'));
39
+ this.addMultisigAddressAsync = util.promisify(this.client.cmd.bind(this.client, 'addmultisigaddress'));
40
+ this.signrawtransactionwithwalletAsync = util.promisify(this.client.cmd.bind(this.client, 'signrawtransactionwithwallet'));
41
+ this.signrawtransactionwithkeyAsync = util.promisify(this.client.cmd.bind(this.client, 'signrawtransactionwithkey'));
42
+ this.importmultiAsync = util.promisify(client.cmd.bind(client, 'importmulti'));
43
+
44
+ this.handleOnEvents(); // Set up event listeners
45
+ this.onReady(); // Prepare for trade execution
46
+ this.tradeStartTime = Date.now();
47
+ }
48
+
49
+ // Other methods for the BuySwapper class (e.g., handleOnEvents, onReady, etc.)
50
+ onReady() {
51
+ return new Promise((resolve, reject) => {
52
+ this.readyRes = resolve;
53
+ // If the readyRes is not called within 60 seconds, terminate the trade
54
+ setTimeout(() => this.terminateTrade('Undefined Error code 1'), 60000);
55
+ });
56
+ }
57
+
58
+ logTime(stage) {
59
+ const currentTime = Date.now();
60
+ console.log(`Time taken for ${stage}: ${currentTime - this.tradeStartTime} ms`);
61
+ }
62
+
63
+ bip67SortPubKeys(pubKeys) {
64
+ return [...pubKeys].sort((a, b) =>
65
+ Buffer.from(a, 'hex').compare(Buffer.from(b, 'hex'))
66
+ );
67
+ }
68
+
69
+ removePreviousListeners() {
70
+ // Correctly using template literals with backticks
71
+ this.socket.off(`${this.cpInfo.socketId}::swap`);
72
+ }
73
+
74
+ delay(ms) {
75
+ return new Promise(resolve => setTimeout(resolve, ms));
76
+ }
77
+
78
+ async ensureFuturesMargin(tradeProps) {
79
+ if (this._futuresMargin) return this._futuresMargin;
80
+
81
+ if (!tradeProps || !tradeProps.contract_id || !tradeProps.price || !tradeProps.amount) {
82
+ throw new Error('Invalid futures trade props for margin calculation');
83
+ }
84
+
85
+ const { contract_id, price, amount } = tradeProps;
86
+
87
+ // 1) Fetch contract info
88
+ const contractInfo = await WalletListener.getContractInfo(contract_id);
89
+ if (!contractInfo) {
90
+ throw new Error(`No contract info for contract ${contract_id}`);
91
+ }
92
+
93
+ // 2) Per-contract margin
94
+ const perContractMargin = await WalletListener.getInitialMargin(
95
+ contract_id,
96
+ price
97
+ );
98
+
99
+ if (!perContractMargin || perContractMargin <= 0) {
100
+ throw new Error('Invalid per-contract margin');
101
+ }
102
+
103
+ // 3) Scale by number of contracts
104
+ const initMargin = perContractMargin * amount;
105
+
106
+ // 4) Collateral propertyId
107
+ const collateral = contractInfo.collateralPropertyId;
108
+
109
+ if (!collateral || initMargin <= 0) {
110
+ throw new Error('Computed invalid futures margin parameters');
111
+ }
112
+
113
+ this._futuresMargin = {
114
+ collateral,
115
+ initMargin,
116
+ perContractMargin,
117
+ leverage: contractInfo.leverage,
118
+ inverse: contractInfo.inverse
119
+ };
120
+
121
+ console.log('[FUTURES] margin prepared', this._futuresMargin);
122
+ return this._futuresMargin;
123
+ }
124
+
125
+
126
+ async sendTxWithSpecRetry(rawTx) {
127
+ const _sendTxWithRetry = async (rawTx, retriesLeft, ms) => {
128
+ try {
129
+ // Attempt to send the transaction
130
+ const result = await this.sendrawtransactionAsync(rawTx);
131
+ // If there's an error and retries are left, try again
132
+ if (result.error && result.error.includes('bad-txns-inputs-missingorspent') && retriesLeft > 0) {
133
+ await new Promise(resolve => setTimeout(resolve, ms));
134
+ console.log('Retrying to send the transaction... Remaining retries:', retriesLeft);
135
+ return _sendTxWithRetry(rawTx, retriesLeft - 1, ms);
136
+ }
137
+ // If successful, return the result
138
+ return result;
139
+ } catch (error) {
140
+ // If an error occurs during sendrawtransactionAsync, handle it here
141
+ console.error('Error during transaction send:', error.message);
142
+ if (retriesLeft > 0) {
143
+ console.log('Retrying after error... Remaining retries:', retriesLeft);
144
+ await new Promise(resolve => setTimeout(resolve, ms));
145
+ return _sendTxWithRetry(rawTx, retriesLeft - 1, ms);
146
+ }
147
+ return { error: 'Transaction failed after retries' }; // Return an error after all retries
148
+ }
149
+ }
150
+
151
+ // Start the retry process with 15 retries and 800ms interval
152
+ return _sendTxWithRetry(rawTx, 15, 1200);
153
+ }
154
+
155
+ async importMultisigNoRescan(address, redeemScriptHex) {
156
+ const request = [{
157
+ scriptPubKey: { address },
158
+ redeemscript: redeemScriptHex,
159
+ watchonly: true,
160
+ timestamp: 'now'
161
+ }];
162
+
163
+ try {
164
+ const result = await this.importmultiAsync(request, { rescan: false });
165
+
166
+ const r = result?.[0];
167
+ if (!r) return;
168
+
169
+ if (!r.success) {
170
+ if (r.error?.code === -4) {
171
+ // Already imported → OK
172
+ console.log('Multisig already present, continuing');
173
+ return;
174
+ }
175
+ throw new Error(r.error?.message || 'importmulti failed');
176
+ }
177
+ } catch (err) {
178
+ throw err;
179
+ }
180
+ }
181
+
182
+ terminateTrade(reason){
183
+ // Emit the TERMINATE_TRADE event to the socket
184
+ const eventData = {event:'TERMINATE_TRADE', socketId: this.myInfo.socketId, reason: reason};
185
+ const tag = `${this.myInfo.socketId}::swap`; // Correct string concatenation
186
+ this.socket.emit(tag, eventData);
187
+ this.removePreviousListeners();
188
+ }
189
+
190
+ handleOnEvents() {
191
+ const eventName = `${this.cpInfo.socketId}::swap`;
192
+ console.log('Received event:', JSON.stringify(eventName));
193
+ this.socket.on(eventName, (eventData) => {
194
+ console.log('event name '+eventData.eventName)
195
+ const { socketId, data } = eventData;
196
+ if (eventData.data?.tradeUUID && eventData.data.tradeUUID !== this.tradeUUID){
197
+ return;
198
+ }
199
+
200
+ switch (eventData.eventName) {
201
+ case 'SELLER:STEP1':
202
+ this.onStep1(socketId,data);
203
+ break;
204
+ case 'SELLER:STEP3':
205
+ this.onStep3(socketId,data);
206
+ break;
207
+ case 'SELLER:STEP5':
208
+ console.log('about to call step 5 func ' +socketId+' '+JSON.stringify(data))
209
+ this.onStep5(socketId,data);
210
+ break;
211
+ default:
212
+ break;
213
+ }
214
+ });
215
+ }
216
+
217
+ // Step 1: Create multisig address and verify
218
+ async onStep1(cpId, msData) {
219
+ console.log('cp socket Id '+JSON.stringify(cpId)+'my CP socketId '+ this.cpInfo.socketId)
220
+ console.log('examining trade info obj '+JSON.stringify(this.tradeInfo))
221
+
222
+ const startStep1Time = Date.now(); // Start timing Step 1
223
+ try {
224
+ // Check that the provided cpId matches the expected socketId
225
+ if (cpId !== this.cpInfo.socketId) {
226
+ console.log('cp socket mismatch '+Boolean(cpId !== this.cpInfo.socketId))
227
+ return new Error(`Error with p2p connection: Socket ID mismatch.`);
228
+ }
229
+
230
+ let pubKeys = bip67SortPubKeys([
231
+ this.cpInfo.keypair.pubkey,
232
+ this.myInfo.keypair.pubkey,
233
+ ]);
234
+ if (this.typeTrade === 'SPOT' && 'propIdDesired' in this.tradeInfo.props){
235
+ let { propIdDesired, propIdForSale } = this.tradeInfo.props;
236
+ if(propIdDesired==0||propIdForSale==0){
237
+ pubKeys = [this.myInfo.keypair.pubkey,this.cpInfo.keypair.pubkey];
238
+ }
239
+ }
240
+ console.log(JSON.stringify(pubKeys))
241
+ const multisigAddress = await this.addMultisigAddressAsync(2, pubKeys);
242
+ console.log('Created Multisig address:', multisigAddress.address, msData.address);
243
+
244
+ if (multisigAddress.address !== msData.address){
245
+ console.log('multisig address mismatch '+msData.address+multisigAddress.address+Boolean(multisigAddress.toString() !== msData.address))
246
+ return new Error('Multisig address mismatch');
247
+ }
248
+
249
+ // Step 4: Validate redeemScript
250
+ if (multisigAddress.redeemScript !== msData.redeemScript) {
251
+ console.log('redeem script mismatch '+multisigAddress.redeemScript+msData.redeemScript+Boolean(multisigAddress.redeemScript !== msData.redeemScript))
252
+ return new Error('Redeem script mismatch');
253
+ }
254
+
255
+ await this.importMultisigNoRescan(multisigAddress.address,multisigAddress.redeemscript)
256
+
257
+ // Step 5: Store the multisig data
258
+ this.multySigChannelData = msData;
259
+
260
+ // Emit the event to the correct socketId
261
+ console.log('about to emit step 2 '+this.myInfo.socketId)
262
+
263
+ const step1Time = Date.now() - startStep1Time; // Time taken for Step 1
264
+ console.log(`Time taken for Step 1: ${step1Time} ms`);
265
+ this.socket.emit(`${this.myInfo.socketId}::swap`, { eventName: 'BUYER:STEP2', socketId: this.myInfo.socketId });
266
+
267
+ } catch (error) {
268
+ this.terminateTrade(`Step 1: ${error.message}`);
269
+ }
270
+ }
271
+
272
+ async onStep3(cpId, commitUTXO) {
273
+ const startStep3Time = Date.now();
274
+ try {
275
+ console.log('cpId and socketId '+cpId+' '+this.cpInfo?.socketId)
276
+ // --- guards ---
277
+ if (cpId !== this.cpInfo?.socketId) throw new Error(`Error with p2p connection`);
278
+
279
+ console.log('multi '+!this.multySigChannelData?.address)
280
+
281
+ if (!this.multySigChannelData?.address) throw new Error(`Wrong Multisig Data Provided`);
282
+
283
+ // --- block height -> expiryBlock ---
284
+ const gbcRes = await this.getBlockCountAsync();
285
+ console.log('gbcRes '+gbcRes)
286
+ if (!Number.isFinite(gbcRes)) throw new Error('Failed to get block count from Litecoin node');
287
+ const bbData = Number(gbcRes) + 10;
288
+
289
+ // --- normalize trade kind (SPOT / FUTURES) ---
290
+ const ti = this.tradeInfo ?? {};
291
+ const props = ti.props ?? {};
292
+ const kindRaw = String(this.typeTrade || ti.type || '').toUpperCase();
293
+ const isSpot = (kindRaw === 'SPOT') || ('propIdDesired' in props) || ('propIdForSale' in props);
294
+ const isFutures = (kindRaw === 'FUTURES') || ('contract_id' in ti) || ('contractId' in ti);
295
+ console.log('isFutures '+isFutures)
296
+ if (!isSpot && !isFutures) throw new Error('Unrecognized Trade Type');
297
+
298
+ // --- column A/B (prefer RPC if available) ---
299
+ let isA = 1; // default A
300
+ try {
301
+ if (typeof WalletListener?.getColumn === 'function') {
302
+ const col = await WalletListener.getColumn(this.myInfo?.keypair?.address, this.cpInfo?.keypair?.address);
303
+ const tag = col?.data ?? col;
304
+ isA = (tag === 'A') ? 0 : 1;
305
+ }
306
+ } catch (_) {
307
+ // keep default isA = 1
308
+ }
309
+
310
+ console.log('column '+isA)
311
+
312
+ // =========================
313
+ // SPOT
314
+ // =========================
315
+ if (isSpot) {
316
+ // safer props
317
+ let {
318
+ propIdDesired = props.propertyId ?? 0,
319
+ amountDesired = props.amount ?? 0,
320
+ amountForSale = props.amountForSale ?? 0,
321
+ propIdForSale = props.propIdForSale ?? 0,
322
+ transfer = props.transfer ?? false,
323
+ sellerIsMaker = props.sellerIsMaker ?? false,
324
+ } = props;
325
+
326
+ const columnAIsMaker = (isA === 1)
327
+ ? (sellerIsMaker ? 1 : 0) // seller is A
328
+ : (!sellerIsMaker ? 1 : 0); // seller is B
329
+
330
+
331
+
332
+ // LTC vs token trade
333
+ let ltcTrade = false;
334
+ let ltcForSale = false;
335
+ if (propIdDesired === 0) {
336
+ ltcTrade = true; // buyer wants LTC -> tokens
337
+ ltcForSale = false;
338
+ } else if (propIdForSale === 0) {
339
+ ltcTrade = true; // seller offers LTC -> buyer pays tokens
340
+ ltcForSale = true; // <-- this was wrong in one earlier snippet
341
+ }
342
+
343
+ if (ltcTrade) {
344
+ // ========== LTC <-> TOKEN (IT) ==========
345
+ const tokenId = ltcForSale ? propIdDesired : propIdForSale;
346
+ const tokensSold = ltcForSale ? amountDesired : amountForSale;
347
+ const satsExpected = ltcForSale ? amountForSale : amountDesired;
348
+
349
+ const payload = Encode.encodeTradeTokenForUTXO({
350
+ propertyId: tokenId,
351
+ amount: tokensSold,
352
+ columnA: isA != 1, // boolean
353
+ satsExpected, // sats expected on-chain
354
+ tokenOutput: 1, // token output index preference (as in your code)
355
+ payToAddress: 0 // same as your call surface
356
+ });
357
+
358
+ const network = this.test ? "LTCTEST" : "LTC";
359
+ const buildOptions = {
360
+ buyerKeyPair: this.myInfo.keypair,
361
+ sellerKeyPair: this.cpInfo.keypair,
362
+ commitUTXOs: [commitUTXO],
363
+ payload,
364
+ amount: satsExpected,
365
+ network
366
+ };
367
+
368
+ const rawHexRes = await buildLitecoinTransaction(buildOptions, this.client);
369
+ if (!rawHexRes?.data?.psbtHex) throw new Error(`Build IT Trade: No PSBT returned`);
370
+
371
+ const step3Time = Date.now() - startStep3Time;
372
+ console.log(`Time taken for Step 3: ${step3Time} ms`);
373
+
374
+ const eventData = {
375
+ eventName: 'BUYER:STEP4',
376
+ socketId: this.myInfo.socketId,
377
+ psbtHex: rawHexRes.data.psbtHex,
378
+ commitTxId: '' // not available here; commit comes from SELLER
379
+ };
380
+ this.socket.emit(`${this.myInfo.socketId}::swap`, eventData);
381
+
382
+ } else {
383
+ // ========== TOKEN <-> TOKEN (Channel) ==========
384
+ // First, fund (commit or transfer) buyer-to-channel for the side they must fund:
385
+ const commitPayload = transfer
386
+ ? Encode.encodeTransfer({
387
+ propertyId: propIdDesired,
388
+ amount: amountDesired,
389
+ isColumnA: isA === 1,
390
+ destinationAddr: this.multySigChannelData.address,
391
+ })
392
+ : Encode.encodeCommit({
393
+ amount: amountDesired,
394
+ propertyId: propIdDesired,
395
+ channelAddress: this.multySigChannelData.address,
396
+ });
397
+
398
+ const network = this.test ? "LTCTEST" : "LTC";
399
+
400
+ // Your NPM flow uses custom builder(s); keeping surface:
401
+ const commitTxConfig = {
402
+ fromKeyPair: this.myInfo.address, // keeping your original shape
403
+ toKeyPair: this.cpInfo.keypair,
404
+ payload: commitPayload,
405
+ network
406
+ };
407
+
408
+ const commitTxRes = await buildTokenTradeTransaction(commitTxConfig, this.client);
409
+ if (!commitTxRes?.signedHex) throw new Error('Failed to sign and send the token transaction');
410
+
411
+ // Extract UTXO from commit hex for chaining
412
+ const utxoData = await getUTXOFromCommit(commitTxRes.signedHex, this.client);
413
+ if (!utxoData) throw new Error('Failed to extract UTXO from commit');
414
+
415
+ // Channel trade payload (tokens-for-tokens)
416
+ const tradePayload = Encode.encodeTradeTokensChannel({
417
+ propertyId1: propIdDesired,
418
+ propertyId2: propIdForSale,
419
+ amountOffered1: amountDesired,
420
+ amountDesired2: amountForSale,
421
+ columnAIsOfferer: isA,
422
+ expiryBlock: bbData,
423
+ columnAIsMaker: columnAIsMaker
424
+ });
425
+ console.log('keypairs '+JSON.stringify(this.myInfo.keypair)+' '+JSON.stringify(this.cpInfo.keypair))
426
+
427
+ const tradeOptions = {
428
+ buyerKeyPair: this.myInfo.keypair,
429
+ sellerKeyPair: this.cpInfo.keypair,
430
+ commitUTXOs: [commitUTXO, utxoData],
431
+ payload: tradePayload,
432
+ amount: 0,
433
+ network
434
+ };
435
+
436
+ const rawHexRes = await buildTokenTradeTransaction(tradeOptions, this.client);
437
+ if (!rawHexRes?.psbtHex) throw new Error(`Build Trade: Failed to build token trade`);
438
+
439
+ const step3Time = Date.now() - startStep3Time;
440
+ console.log(`Time taken for Step 3: ${step3Time} ms`);
441
+
442
+ this.socket.emit(
443
+ `${this.myInfo.socketId}::swap`,
444
+ { eventName: 'BUYER:STEP4', socketId: this.myInfo.socketId, psbtHex: rawHexRes.psbtHex, commitTxId: commitTxRes.signedHex }
445
+ );
446
+ }
447
+
448
+ return; // done with SPOT
449
+ }
450
+
451
+ // =========================
452
+ // FUTURES
453
+ // =========================
454
+ if(isFutures){
455
+ const trade = ti; // your desktop shape puts futures fields at top-level, not in props
456
+ const {
457
+ contract_id,
458
+ amount,
459
+ price,
460
+ transfer = props.transfer ?? false,
461
+ sellerIsMaker = props.sellerIsMaker ?? false
462
+ } = trade.props;
463
+
464
+ console.log('trade props '+JSON.stringify(ti)+' '+JSON.stringify(trade))
465
+
466
+ const margin = await this.ensureFuturesMargin(trade.props)
467
+ const initMargin= margin.initMargin
468
+ const collateral= margin.collateral
469
+
470
+
471
+ console.log('margin and collateral '+initMargin+' '+collateral)
472
+
473
+ // column/maker role (desktop logic)
474
+ const columnAIsMaker = (isA === 1)
475
+ ? (sellerIsMaker ? 1 : 0) // seller is A
476
+ : (!sellerIsMaker ? 1 : 0); // seller is B
477
+
478
+ // commit or transfer futures collateral
479
+ const commitPayload = transfer
480
+ ? Encode.encodeTransfer({
481
+ propertyId: collateral,
482
+ amount: initMargin,
483
+ isColumnA: isA === 1,
484
+ destinationAddr: this.multySigChannelData.address,
485
+ })
486
+ : Encode.encodeCommit({
487
+ propertyId: collateral,
488
+ amount: initMargin,
489
+ channelAddress: this.multySigChannelData.address,
490
+ });
491
+
492
+ console.log('payload '+commitPayload)
493
+ // In buyer's onStep3:
494
+
495
+ // Build, sign, and broadcast the commit transaction
496
+ // This function will call listUnspent internally to get buyer's UTXO
497
+ const commitTxRes = await buildSignAndBroadcastCommitTx({
498
+ buyerKeyPair: this.myInfo.keypair,
499
+ sellerKeyPair: this.cpInfo.keypair,
500
+ payload: commitPayload, // The commit payload (tl45...)
501
+ multySigChannelData: this.multySigChannelData
502
+ }, this.client);
503
+
504
+ console.log('[STEP3] Commit tx broadcast:', JSON.stringify({
505
+ txid: commitTxRes.txid,
506
+ broadcast: commitTxRes.broadcast
507
+ }));
508
+
509
+ // The commit UTXO is already in the response
510
+ const utxoData = commitTxRes.commitUtxoData;
511
+ console.log('[STEP3] Commit UTXO:', JSON.stringify(utxoData));
512
+
513
+ // Now build the settlement transaction payload
514
+ const channelPayload = Encode.encodeTradeContractChannel({
515
+ contractId: contract_id,
516
+ amount,
517
+ price,
518
+ expiryBlock: bbData,
519
+ columnAIsSeller: isA,
520
+ insurance: false,
521
+ columnAIsMaker
522
+ });
523
+
524
+ // Build the settlement transaction (unsigned)
525
+ const settlementTxRes = await buildFuturesTransaction({
526
+ buyerKeyPair: this.myInfo.keypair,
527
+ sellerKeyPair: this.cpInfo.keypair,
528
+ commitUTXOs: [utxoData], // The UTXO we just created
529
+ payload: channelPayload
530
+ }, this.client);
531
+
532
+ // Emit to seller
533
+ this.socket.emit(`${this.myInfo.socketId}::swap`, {
534
+ eventName: 'BUYER:STEP4',
535
+ socketId: this.myInfo.socketId,
536
+ data: {
537
+ psbtHex: settlementTxRes.psbtHex,
538
+ commitHex: commitTxRes.signedHex,
539
+ commitTxId: commitTxRes.txid,
540
+ prevTxs: settlementTxRes.prevTxs
541
+ }
542
+ });
543
+
544
+ return;
545
+ }
546
+
547
+ throw new Error(`Unrecognized Trade Type: ${this.typeTrade}`);
548
+ } catch (error) {
549
+ const errorMessage = error?.message || 'Undefined Error';
550
+ this.terminateTrade(`Step 3: ${errorMessage}`);
551
+ }
552
+ }
553
+
554
+
555
+ // Step 5: Sign the PSBT using Litecore and send the final transaction
556
+ async onStep5(cpId, psbtHex) {
557
+ const startStep5Time = Date.now();
558
+
559
+ /*let signed = await signpsbtAsync(psbtHex.data.psbt)
560
+ const final = await finalizeAsync(signed.psbt)
561
+ console.log('final '+JSON.stringify(final))
562
+
563
+ const timeToCoSign = Date.now()-this.tradeStartTime
564
+ console.log('Cosigned trade in '+timeToCoSign)
565
+
566
+
567
+ console.log(sentTx)
568
+ const psbt = Psbt.fromHex(psbtHex);
569
+ const bigIntReplacer = (key, value) => {
570
+ if (typeof value === 'bigint') {
571
+ return value.toString(); // Convert BigInt to string
572
+ }
573
+ return value;
574
+ };*/
575
+
576
+ // Now, use this replacer when calling JSON.stringify
577
+
578
+
579
+ // Ensure that each input has the necessary witness data
580
+
581
+ try{
582
+ // Sign the PSBT transaction using the wallet
583
+ let wif = await this.dumpprivkeyAsync(this.myInfo.keypair.address)
584
+ console.log('wif '+wif)
585
+ let network = "LTC"
586
+ if(this.test==true){
587
+ network = "LTCTEST"
588
+ }
589
+ //console.log('network')
590
+ //const signedPsbt = await signpsbtAsync(psbtHex,true)
591
+ const signedPsbt = await signPsbtRawTx({wif:wif,network:network,psbtHex:psbtHex}, this.client);
592
+ wif = ''
593
+ //if (!signedPsbt || !signedPsbt.hex) return new Error('Failed to sign PSBT');
594
+ const timeToCoSign = Date.now()-this.tradeStartTime
595
+ console.log('Cosigned trade in '+timeToCoSign)
596
+ console.log('complete psbt hex, finished? '+signedPsbt.data.isFinished+' '+signedPsbt.data.psbtHex)
597
+
598
+ /*const psbtDecode = await decodepsbtAsync(signedPsbt.data.psbtHex)
599
+ console.log(psbtDecode)*/
600
+
601
+ const sentTx = await this.sendTxWithSpecRetry(signedPsbt.data.finalHex);
602
+ //console.log(JSON.stringify(Psbt.fromHex(signedPsbt.data.psbtHex), bigIntReplacer))
603
+ /*const decode = await decoderawtransactionAsync(signedPsbt.data.hex)
604
+ console.log('decoded final tx '+ JSON.stringify(decode))
605
+
606
+ // Send the signed transaction
607
+ const sentTx = await sendrawtransactionAsync(signedPsbt.data.hex);
608
+ if (!sentTx) return new Error('Failed to send the transaction');
609
+ */
610
+ // Emit the next step event
611
+ const step5Time = Date.now() - startStep5Time; // Time taken for Step 3
612
+ //console.log(`Time taken for Step 5: ${step5Time} ms`);
613
+
614
+ console.log('checking socket id'+this.myInfo.socketId)
615
+ this.socket.emit(`${this.myInfo.socketId}::swap`, { eventName: 'BUYER:STEP6', socketId: this.myInfo.socketId, data: sentTx });
616
+ } catch (error) {
617
+ this.terminateTrade(`Step 5: ${error.message}`);
618
+ }
619
+ }
620
+ }
621
+
622
+ module.exports = BuySwapper;
package/client.js ADDED
@@ -0,0 +1,50 @@
1
+ const Litecoin = require('litecoin');
2
+ const Bitcoin = require('bitcoin')
3
+ const { RelayerClient, createFallbackClient, DEFAULT_RELAYER_HOST, DEFAULT_RELAYER_PORT } = require('./relayerClient');
4
+
5
+ const createLitecoinClient = (test = true, relayerOpts) => {
6
+ const config = {
7
+ host: '127.0.0.1',
8
+ port: test ? 19332 : 9332, // Switch between testnet and mainnet
9
+ user: 'user', // Make sure to replace these with your actual credentials
10
+ pass: 'pass',
11
+ timeout: 10000
12
+ };
13
+
14
+ const local = new Litecoin.Client(config);
15
+
16
+ if (relayerOpts === false) {
17
+ // Explicitly disabled
18
+ return local;
19
+ }
20
+
21
+ return createFallbackClient(local, relayerOpts || {});
22
+ };
23
+
24
+ const createBitcoinClient = (test = true, relayerOpts) => {
25
+ const config = {
26
+ host: '127.0.0.1',
27
+ port: test ? 18332 : 8332, // Switch between testnet and mainnet
28
+ user: 'user', // Make sure to replace these with your actual credentials
29
+ pass: 'pass',
30
+ timeout: 10000
31
+ };
32
+
33
+ const local = new Bitcoin.Client(config);
34
+
35
+ if (relayerOpts === false) {
36
+ return local;
37
+ }
38
+
39
+ return createFallbackClient(local, relayerOpts || {});
40
+ };
41
+
42
+ /**
43
+ * Create a relayer-only client (no local node needed).
44
+ */
45
+ const createRelayerOnlyClient = (opts) => {
46
+ return new RelayerClient(opts);
47
+ };
48
+
49
+
50
+ module.exports = {createLitecoinClient, createBitcoinClient, createRelayerOnlyClient};