@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
@@ -0,0 +1,1702 @@
1
+
2
+ const TradeChannels = require('./channels.js')
3
+ const Activation = require('./activation.js')
4
+ const activation = Activation.getInstance();
5
+ // Custom modules for TradeLayer
6
+ //const Clearing =require('./clearing.js')
7
+ //const Persistence = require('./Persistence.js'); // Handles data persistence
8
+ const Orderbook = require('./orderbook.js'); // Manages the order book
9
+ //const InsuranceFund = require('./insurance.js'); // Manages the insurance fund
10
+ //const VolumeIndex = require('./VolumeIndex.js'); // Tracks and indexes trading volumes
11
+ const TradeLayerManager = require('./vesting.js'); // Handles vesting logic
12
+ //const ReOrgChecker = require('./reOrg.js');
13
+ const OracleList = require('./oracle.js')
14
+ // Additional modules
15
+ const fs = require('fs'); // File system module
16
+
17
+ const Validity = require('./validity.js'); // Module for checking transaction validity
18
+ const TxUtils = require('./txUtils.js'); // Utility functions for transactions
19
+ const TxIndex = require('./txIndex.js') // Indexes TradeLayer transactions
20
+ const TallyMap = require('./tally.js'); // Manages Tally Mapping
21
+ const MarginMap = require('./marginMap.js'); // Manages Margin Mapping
22
+ const PropertyManager = require('./property.js'); // Manages properties
23
+ const ContractRegistry = require('./contractRegistry.js'); // Registry for contracts
24
+ const ClearList = require('./clearlist.js')
25
+ const Scaling = require('./scaling.js')
26
+ //const Consensus = require('./consensus.js'); // Functions for handling consensus
27
+ const Channels = require('./channels.js')
28
+ const Encode = require('./txEncoder.js'); // Encodes transactions
29
+ const Types = require('./types.js'); // Defines different types used in the system
30
+ const Decode = require('./txDecoder.js'); // Decodes transactionsconst db = require('./db.js'); // Adjust the path if necessary
31
+ const db = require('./db.js'); // Adjust the path if necessary
32
+ const BigNumber = require('bignumber.js')
33
+ const VolumeIndex = require('./volumeIndex.js')
34
+ const SynthRegistry = require('./vaults.js')
35
+ const TradeHistory = require('./tradeHistoryManager.js')
36
+ const OptionsEngine = require('./options.js');
37
+
38
+ // logic.js
39
+ const Logic = {
40
+ //here we have a kinda stupid structure where instead of passing the params obj. I break it down into its sub-properties
41
+ //and have to map the subsequent function's parameter sequence to how I have it here
42
+ //I've wasted a lot of time fixing small bugs relating to getting this right for each functiom, would do it differently
43
+ //Anyway, here we branch into each logic function.
44
+ async typeSwitch(txNumber, params){
45
+ if(params.valid == false){return null}
46
+ console.log('tx number and params ' +txNumber, params)
47
+ switch (txNumber) {
48
+ case 0:
49
+ await Logic.activateTradeLayer(params.txTypesToActivate, params.block, params.codeHash);
50
+ break;
51
+ case 1:
52
+ await Logic.tokenIssue(params.senderAddress, params.initialAmount, params.ticker, params.url, params.whitelistId, params.isManaged, params.backupAddress, params.isNFT, params.block);
53
+ break;
54
+ case 2:
55
+ await Logic.sendToken(params.sendAll, params.senderAddress, params.address, params.propertyIds, params.amounts,params.block);
56
+ break;
57
+ case 3:
58
+ console.log('about to call utxo trade logic '+JSON.stringify(params))
59
+ await Logic.tradeTokenForUTXO(params.senderAddress, params.satsPaymentAddress, params.propertyId, params.amount, params.columnA, params.satsExpected, params.tokenDeliveryAddress, params.satsReceived, params.price, params.paymentPercent, params.tagWithdraw, params.block, params.txid);
60
+ break;
61
+ case 4:
62
+ console.log('in the commit case '+params.txid)
63
+ await Logic.commitToken(params.senderAddress, params.channelAddress, params.propertyId, params.amount, params.payEnabled, params.clearLists, params.block, params.txid);
64
+ break;
65
+ case 5:
66
+ await Logic.onChainTokenToToken(params.senderAddress, params.propertyIdOffered, params.propertyIdDesired, params.amountOffered, params.amountExpected, params.txid, params.block, params.stop, params.post);
67
+ break;
68
+ case 6:
69
+ await Logic.cancelOrder(params.senderAddress, params.isContract, params.offeredPropertyId, params.desiredPropertyId, params.cancelAll, params.cancelParams, params.block);
70
+ break;
71
+ case 7:
72
+ await Logic.createClearList(sender, params.name, params.url, params.description, params.backupAddress, params.block);
73
+ break;
74
+ case 8:
75
+ await Logic.updateAdmin(params.whitelist, params.token, params.oracle, params.id, params.newAddress, params.updateBackup, params.block);
76
+ break;
77
+ case 9:
78
+ await Logic.issueOrRevokeAttestation(params.sender, params.id, params.targetAddress, params.metaData, params.revoke, params.block);
79
+ break;
80
+ case 10:
81
+ await Logic.AMMPool(params.senderAddress, params.block, params.isRedeem, params.isContract, params.id1, params.amount, params.id2, params.amount2);
82
+ break;
83
+ case 11:
84
+ await Logic.grantManagedToken(params.propertyId, params.amount, params.recipientAddress, params.propertyManager, params.senderAddress, params.block);
85
+ break;
86
+ case 12:
87
+ await Logic.redeemManagedToken(params.propertyId, params.amount, params.propertyManager, params.senderAddress, params.block);
88
+ break;
89
+ case 13:
90
+ await Logic.createOracle(params.senderAddress, params.ticker, params.url, params.backupAddress, params.clearlists, params.lag, params.oracleRegistry, params.block);
91
+ break;
92
+ case 14:
93
+ await Logic.publishOracleData(params.oracleId, params.price, params.high, params.low, params.close, params.block);
94
+ break;
95
+ case 15:
96
+ await Logic.closeOracle(params.oracleId, params.oracleRegistry, params.block);
97
+ break;
98
+ case 16:
99
+ await Logic.createContractSeries(params.senderAddress, params.native, params.underlyingOracleId, params.onChainData, params.notionalPropertyId, params.notionalValue, params.collateralPropertyId, params.leverage, params.expiryPeriod, params.series, params.inverse, params.fee, params.block, params.whitelist);
100
+ break;
101
+ case 17:
102
+ await Logic.exerciseDerivative(params.contractId, params.amount, params.contractsRegistry,params.senderAddress, params.block);
103
+ break;
104
+ case 18:
105
+ await Logic.tradeContractOnchain(params.contractId, params.price, params.amount, params.sell, params.insurance, params.block, params.txid, params.senderAddress, params.reduce, params.post, params.stop,params.block);
106
+ break;
107
+ case 19:
108
+ await Logic.tradeContractChannel(params.contractId, params.price, params.amount, params.columnAIsSeller, params.expiryBlock, params.insurance, params.senderAddress, params.block,params.txid,params.columnAIsMaker);
109
+ break;
110
+ case 20:
111
+ await Logic.tradeTokensChannel(params.propertyIdOffered, params.propertyIdDesired, params.amountOffered, params.amountDesired, params.expiryBlock, params.columnAIsOfferer, params.senderAddress, params.block,params.txid,params.columnAIsMaker);
112
+ break;
113
+ case 21:
114
+ await Logic.withdrawal(params.withdrawAll, params.channelAddress, params.propertyId, params.amount, params.senderAddress, params.block, params.columnIsB);
115
+ break;
116
+ case 22:
117
+ await Logic.transfer(params.senderAddress, params.toChannelAddress, params.propertyId, params.amount, params.isColumnA, params.pay, params.payRefAddress, params.block,params.txid);
118
+ break;
119
+ case 23:
120
+ await Logic.settleChannelPNL(params.channelAddress, params.txParams, params.block,params.txid);
121
+ break;
122
+ case 24:
123
+ await Logic.mintSynthetic(params.senderAddress, params.propertyId, params.contractId, params.amount, params.block, params.grossRequired, params.contracts, params.margin);
124
+ break;
125
+ case 25:
126
+ await Logic.redeemSynthetic(params.senderAddress, params.propertyId, params.contractId, params.amount, params.block);
127
+ break;
128
+ case 26:
129
+ await Logic.payToTokens(params.tallyMap, params.propertyIdTarget, params.propertyIdUsed, params.amount, params.block);
130
+ break;
131
+ case 27:
132
+ await processOptionTrade(sender, params, txid);
133
+ break;
134
+ case 28:
135
+ await Logic.tradeBaiUrbun(params.channelAddress, params.propertyIdDownPayment, params.propertyIdToBeSold, params.downPaymentPercent, params.amount, params.expiryBlock, params.tradeExpiryBlock, params.block);
136
+ break;
137
+ case 29:
138
+ await Logic.tradeMurabaha(params.channelAddress, params.buyerAddress, params.sellerAddress, params.propertyId, params.costPrice, params.profitMargin, params.paymentBlockHeight, params.block);
139
+ break;
140
+ case 30:
141
+ await Logic.issueInvoice(params.propertyManager, params.invoiceRegistry, params.propertyIdToReceivePayment, params.amount, params.dueDateBlock, params.propertyIdCollateral, params.receivesPayToToken, params.issuerNonce, params.block);
142
+ break;
143
+ case 31:
144
+ Logic.batchSettlement(params);
145
+ break;
146
+ case 32:
147
+ await Logic.batchMoveZkRollup(params.zkVerifier, params.rollupData, params.zkProof, params.block);
148
+ break;
149
+ case 33:
150
+ Logic.coloredCoin(params);
151
+ break;
152
+ case 34:
153
+ Logic.crossLayerBridge(params);
154
+ break;
155
+ case 35:
156
+ Logic.smartContractBind(params);
157
+ break;
158
+ default:
159
+ console.log(`Unhandled transaction type: ${txNumber}`);
160
+ }
161
+ return
162
+ },
163
+
164
+ async activateTradeLayer(txTypes, block, codeHash) {
165
+ if (!Array.isArray(txTypes)) {
166
+ txTypes = [txTypes];
167
+ }
168
+ console.log('inside activate logic '+txTypes)
169
+ const results = [];
170
+ for (const txType of txTypes) {
171
+ console.log(`Activating txType: ${txType} at block: ${block}`);
172
+ const activationResult = await activation.activate(txType, block, codeHash);
173
+ console.log(`Activation result for txType ${txType}:`, activationResult);
174
+ results.push({ txType, result: activationResult });
175
+ }
176
+
177
+ return results; // Return an array of results for further processing
178
+ },
179
+
180
+
181
+ async tokenIssue(sender, initialAmount, ticker, url = '', clearlistId = 0, isManaged = false, backupAddress = '', isNFT = false, block) {
182
+ const propertyManager = PropertyManager.getInstance();
183
+
184
+ // Determine the type of the token based on whether it's managed or an NFT
185
+ let tokenType = isNFT ? 'Non-Fungible' : isManaged ? 'Managed' : 'Fixed';
186
+
187
+ // Define the token data
188
+ const tokenData = {
189
+ ticker: ticker,
190
+ totalInCirculation: initialAmount,
191
+ type: tokenType,
192
+ clearlistId: clearlistId,
193
+ issuer: sender,
194
+ backupAddress: backupAddress
195
+ };
196
+
197
+ // Create the token in the property manager
198
+ try {
199
+ var newPropertyId = await propertyManager.createToken(ticker, initialAmount, tokenType, clearlistId, sender, backupAddress);
200
+ //console.log('created token, now creating the units at '+sender+ ' in amount '+initialAmount)
201
+ await TallyMap.updateBalance(sender, newPropertyId, initialAmount, 0, 0, 0,'issuance',block);
202
+ return `Token ${ticker} (ID: ${newPropertyId}) created. Type: ${tokenType}`;
203
+ } catch (error) {
204
+ console.error('Error creating token:', error);
205
+ return error.message;
206
+ }
207
+ },
208
+
209
+
210
+ async sendToken(sendAll, senderAddress, recipientAddresses, propertyIdNumbers, amounts,block) {
211
+ console.log('send logic parameters '+sendAll + ' '+ senderAddress + ' '+ recipientAddresses + ' ' + propertyIdNumbers + ' '+ amounts)
212
+ if (sendAll) {
213
+ // Handle sending all available balances
214
+ //console.log('sendingAll')
215
+ await sendAll(senderAddress,recipientAddresses)
216
+ } else {
217
+ // Check if handling a multi-send or single send
218
+ const isMultiSend = Array.isArray(propertyIdNumbers) && Array.isArray(amounts);
219
+ if (isMultiSend) {
220
+ //console.log('multisend '+ isMultiSend + ' is this an array? '+propertyIdNumbers+ ' what about amounts '+amounts)
221
+ // Ensure arrays are of the same length
222
+ if (propertyIdNumbers.length !== amounts.length || propertyIdNumbers.length !== recipientAddresses.length) {
223
+ throw new Error('Property IDs, amounts, and recipient addresses arrays must have the same length.');
224
+ }
225
+
226
+ // Process each send in the multi-send transaction
227
+ for (let i = 0; i < propertyIdNumbers.length; i++) {
228
+ const propertyId = propertyIdNumbers[i];
229
+ const amount = amounts[i];
230
+ const recipientAddress = recipientAddresses[i];
231
+ console.log('checking block before process send' +block)
232
+ await processSend(senderAddress, recipientAddress, propertyId, amount,block);
233
+ }
234
+ } else {
235
+ // Special handling for TLVEST (Property ID 2)
236
+ //console.log('propertyIdnumbers ' +propertyIdNumbers)
237
+ if (propertyIdNumbers == 2||propertyIdNumbers==3) {
238
+ console.log('vesting single send '+senderAddress)
239
+ await this.vestingSend(senderAddress,recipientAddresses,propertyIdNumbers,amounts,block)
240
+ }else if(propertyIdNumbers!=undefined){
241
+ console.log('vanilla single send, block '+block)
242
+ await this.sendSingle(senderAddress, recipientAddresses, propertyIdNumbers, amounts,block);
243
+ }
244
+ }
245
+ }
246
+
247
+ // Save the updated tally map to the database
248
+ //await TallyMap.recordTallyMapDelta(blockHeight, txId, address, propertyId, amountChange)
249
+ return console.log('sent')
250
+ },
251
+
252
+ async vestingSend(senderAddress, recipientAddresses, propertyIdNumbers, amounts,block){
253
+ // Get TLVEST and TL balances for the sender
254
+
255
+ const BigNumber = require('bignumber.js');
256
+
257
+ // Ensuring amount is a whole number
258
+ const roundedAmount = new BigNumber(amounts).integerValue(BigNumber.ROUND_DOWN);
259
+
260
+ if (roundedAmount.isLessThanOrEqualTo(0)) {
261
+ throw new Error("Amount must be greater than zero");
262
+ }
263
+
264
+ const tlVestTally = await TallyMap.getTally(senderAddress, propertyIdNumbers);
265
+
266
+ // Calculate the amount of TL to move from vesting to available
267
+ const tlVestingMovement = this.calculateVestingMovement(amounts, tlVestTally)
268
+
269
+ await TallyMap.updateBalance(senderAddress, propertyIdNumbers, -amounts, 0, 0, 0,'vestingSend',block);
270
+ await TallyMap.updateBalance(recipientAddresses, propertyIdNumbers, amounts, 0, 0, 0,'vestingSend',block);
271
+
272
+ await TallyMap.updateBalance(senderAddress, propertyIdNumbers, 0, 0, 0, -tlVestingMovement,'vestingDrag',block);
273
+ await TallyMap.updateBalance(recipientAddresses, propertyIdNumbers, 0, 0, 0, tlVestingMovement,'vestingFollow',block);
274
+ return
275
+ },
276
+
277
+ calculateVestingMovement(amount, tlVestTally) {
278
+ // Convert all values to BigNumber for accurate calculation
279
+ const amountBN = new BigNumber(amount);
280
+ const tlVestAvailableBN = new BigNumber(tlVestTally.available);
281
+ const tlVestingBN = new BigNumber(tlVestTally.vesting);
282
+
283
+ // Calculate the proportion of TLVEST being moved
284
+ // Using BigNumber's division method for precision
285
+ const proportionBN = amountBN.dividedBy(tlVestAvailableBN);
286
+
287
+ // Calculate the amount of TL to move from vesting to available
288
+ // Ensure result is rounded down to avoid fractional vesting movement
289
+ const tlVestingMovementBN = tlVestingBN.multipliedBy(proportionBN).integerValue(BigNumber.ROUND_DOWN);
290
+ console.log('inside calc vesting mov '+tlVestingMovementBN+' '+tlVestingBN+' '+proportionBN+' '+amountBN+' '+tlVestAvailableBN+' '+amount+' '+tlVestTally.available+' '+tlVestTally.vesting)
291
+ return tlVestingMovementBN.toString(); // Convert back to string for further processing
292
+ },
293
+
294
+
295
+ roundToEightDecimals(number) {
296
+ return Math.floor(number * 1e8) / 1e8;
297
+ },
298
+
299
+
300
+ async sendSingle(senderAddress, receiverAddress, propertyId, amount,block) {
301
+ const tallyMapInstance = await TallyMap.getInstance();
302
+
303
+ // Check if sender has enough balance
304
+ const senderBalance = TallyMap.getTally(senderAddress, propertyId);
305
+ console.log('checking balance before sending ' +JSON.stringify(senderBalance))
306
+ if (senderBalance < amount) {
307
+ /*throw new Error*/console.log("Insufficient balance");
308
+ }
309
+
310
+ // Perform the send operation
311
+ await TallyMap.updateBalance(senderAddress, propertyId, -amount, 0, 0, 0,'send', block);
312
+ await TallyMap.updateBalance(receiverAddress, propertyId, amount, 0, 0, 0,'receive', block);
313
+
314
+ // Handle special case for TLVEST
315
+ if (propertyId === 2) {
316
+ // Update the vesting column of TL accordingly
317
+ // Logic for updating TL vesting...
318
+ }
319
+
320
+ return "Send operation successful";
321
+ },
322
+
323
+ async sendAll(senderAddress, receiverAddress) {
324
+ const tallyMapInstance = await TallyMap.getInstance();
325
+
326
+ // Get all balances for the sender
327
+ const senderBalances = tallyMapInstance.getAddressBalances(senderAddress);
328
+
329
+ if (senderBalances.length === 0) {
330
+ throw new Error("No balances to send");
331
+ }
332
+
333
+ // Iterate through each token balance and send it to the receiver
334
+ for (const balance of senderBalances) {
335
+ const { propertyId, amount } = balance;
336
+ if (amount > 0) {
337
+ await TallyMap.updateBalance(senderAddress, propertyId, -amount, 0, 0, 0, 'sendAll');
338
+ await TallyMap.updateBalance(receiverAddress, propertyId, amount, 0, 0, 0,'receiveAll');
339
+
340
+ // Handle special case for TLVEST
341
+ if (propertyId === 'TLVEST') {
342
+ // Update the vesting column of TL accordingly
343
+ // Logic for updating TL vesting...
344
+ }
345
+ }
346
+ }
347
+
348
+ return "All balances sent successfully";
349
+ },
350
+
351
+ // Helper function to process a single send operation
352
+ async processSend(senderAddress, recipientAddress, propertyId, amount,block) {
353
+
354
+ const availableBalance = tallyMap.getAvailableBalance(senderAddress, propertyId);
355
+ if (availableBalance < amount) {
356
+ throw new Error('Insufficient available balance for transaction.');
357
+ }
358
+
359
+ await TallyMap.updateBalance(senderAddress, propertyId, -amount,0,0,0,'multi-send',block);
360
+ await TallyMap.updateBalance(recipientAddress, propertyId, amount,0,0,0,'multi-send',block);
361
+ console.log(`Transferred ${amount} of property ${propertyId} from ${senderAddress} to ${recipientAddress}`);
362
+ return
363
+ },
364
+
365
+ async tradeTokenForUTXO(senderAddress, receiverAddress, propertyId, tokenAmount, columnA, satsExpected, tokenDeliveryAddress, satsReceived, price, paymentPercent, tagWithdraw, block, txid) {
366
+ // Calculate the number of tokens to deliver based on the LTC received
367
+ const receiverLTCReceivedBigNumber = new BigNumber(satsReceived);
368
+ const satsExpectedBigNumber = new BigNumber(satsExpected);
369
+ const decodedTokenAmountBigNumber = new BigNumber(tokenAmount);
370
+ const tradeHistoryManager = new TradeHistory()
371
+
372
+ const tokensToDeliver = Number(tokenAmount)
373
+ //console.log('values in utxo logic '+tokenAmount+' '+decodedTokenAmountBigNumber+' '+satsExpected+' '+satsExpectedBigNumber+' '+satsReceived+' '+receiverLTCReceivedBigNumber)
374
+ //look at the channel balance where the commited tokens we're selling for LTC exist
375
+
376
+ console.log('inside logic for UTXO trade '+tokensToDeliver+' '+price, columnA)
377
+ let channel = await Channels.getChannel(senderAddress);
378
+ if(!channel){
379
+ console.log('failed UTXO trade no commited tokens ')
380
+ return
381
+ }
382
+ let channelBalance;
383
+
384
+ // Default to column with balance if specified column has none
385
+ if (columnA === true) {
386
+ channelBalance = channel["A"]?.[propertyId] || 0;
387
+ if (channelBalance === 0) {
388
+ console.log(`No balance in column A. Defaulting to column B.`);
389
+ columnA = false; // Switch to column B
390
+ channelBalance = channel["B"]?.[propertyId] || 0;
391
+ }
392
+ } else if (columnA === false) {
393
+ channelBalance = channel["B"]?.[propertyId] || 0;
394
+ if (channelBalance === 0) {
395
+ console.log(`No balance in column B. Defaulting to column A.`);
396
+ columnA = true; // Switch to column A
397
+ channelBalance = channel["A"]?.[propertyId] || 0;
398
+ }
399
+ }
400
+
401
+ // If both columns are empty, handle the failure
402
+ if (channelBalance === 0) {
403
+ console.log(`No balance available in either column for property ID ${propertyId}`);
404
+ return; // Exit early, or set tokensToDeliver to 0 as appropriate
405
+ }
406
+
407
+ // Ensure tokensToDeliver does not exceed available balance
408
+ if (tokensToDeliver > channelBalance) {
409
+ tokensToDeliver = channelBalance;
410
+ }
411
+ console.log(`${tokensToDeliver} tokens to deliver out of ${channelBalance} available`);
412
+
413
+ // Debit tokens from the correct column
414
+ if (columnA === true) {
415
+ channel["A"][propertyId] -= tokensToDeliver;
416
+ } else if (columnA === false) {
417
+ channel["B"][propertyId] -= tokensToDeliver;
418
+ }
419
+
420
+ // Save updated channel state
421
+ await Channels.setChannel(senderAddress, channel);
422
+
423
+ console.log('channel adjusted for token sale '+JSON.stringify(channel["A"])+' '+JSON.stringify(channel["B"]))
424
+ //the tokens exist both as channel object balances and reserve balance on the channel address, which is the sender
425
+ //So we debit there and then credit them to the token delivery address, which we took in the parsing
426
+ //From the token delivery vOut and analyzing the actual transaction, usually the change address of the LTC spender
427
+ await TallyMap.updateChannelBalance(senderAddress,propertyId,-tokensToDeliver,'UTXOTokenTradeDebit',block)
428
+ const feeRateBN = new BigNumber(0.00005)
429
+ const fee = new BigNumber(tokenAmount).times(feeRateBN).decimalPlaces(8).toNumber()
430
+ const netDelivery = new BigNumber(tokensToDeliver).minus(fee).decimalPlaces(8).toNumber()
431
+ if(tagWithdraw!=null&&typeof tagWithdraw==="string" ){
432
+ await TallyMap.updateChannelBalance(tokenDeliveryAddress,propertyId,netDelivery,'UTXOTokenTradeCredit',block)
433
+ await Channels.recordCommitToChannel(tokenDeliveryAddress, tagWithdraw, propertyId, tokenAmount, false, null, block)
434
+ }else{
435
+ await TallyMap.updateBalance(tokenDeliveryAddress,propertyId,netDelivery,0,0,0,'UTXOTokenTradeCredit',block)
436
+ }
437
+ await TallyMap.updateBalance(tokenDeliveryAddress, propertyId, -fee, 0, 0, 0, "utxoFee", block,txid)
438
+ console.log('about to apply fee cache '+propertyId+' '+fee)
439
+ await TallyMap.updateFeeCache(propertyId,fee,1,block)
440
+ const key = '0-'+propertyId
441
+ console.log('saving volume in volume Index '+key+' '+satsReceived)
442
+ const coinAdj = new BigNumber(satsReceived).div(1e8).decimalPlaces(8, BigNumber.ROUND_DOWN)
443
+ console.log(' price in UTXO '+price)
444
+ if (!Number.isFinite(Number(price))) {
445
+ price = coinAdj.div(tokenAmount).decimalPlaces(8).toNumber();
446
+ }
447
+
448
+ await VolumeIndex.saveVolumeDataById(
449
+ key,
450
+ tokenAmount,
451
+ coinAdj.toNumber(),
452
+ price,
453
+ block,
454
+ 'UTXO')
455
+
456
+ const trade = {
457
+ offeredPropertyId: 0,
458
+ desiredPropertyId: propertyId,
459
+ amountOffered: tokenAmount, // or appropriate amount
460
+ amountExpected: coinAdj.toNumber(), // or appropriate amount
461
+ price: price,
462
+ takerFee: fee,
463
+ block: block,
464
+ buyer: tokenDeliveryAddress,
465
+ seller: receiverAddress,
466
+ takerTxId: txid
467
+ };
468
+ const orderbook = await Orderbook.getOrderbookInstance(key)
469
+ await orderbook.recordTokenTrade(trade,block,txid)
470
+ TallyMap.updateFeeCache(propertyId,fee,1,block)
471
+ const isListedA = await ClearList.isAddressInClearlist(2, senderAddress);
472
+ const isListedB = await ClearList.isAddressInClearlist(2, receiverAddress)
473
+ let isTokenListed = false
474
+ if (String(propertyId).startsWith('s-')) {
475
+ isTokenListed = true //need to add logic to look up the contractId inline to the synth id and then look up its pairs
476
+ // and then look up if those tokens are listed
477
+ }else{
478
+ let propertyInfo = PropertyManager.getPropertyData(propertyId)
479
+ if(propertyInfo.issuer){
480
+ isTokenListed = await ClearList.isAddressInClearlist(1, propertyInfo.issuer);
481
+ }
482
+ }
483
+ console.log('is token/address listed for liquidity reward '+isListedA+' '+isListedB+' '+isTokenListed)
484
+ if(isTokenListed){
485
+ const liqRewardBaseline1= await VolumeIndex.baselineLiquidityReward(satsReceived,0.000025,0)
486
+ const liqRewardBaseline2= await VolumeIndex.baselineLiquidityReward(tokenAmount,0.000025,propertyId)
487
+ TallyMap.updateBalance(senderAddress,3,liqRewardBaseline1,0,0,0,'baselineLiquidityReward')
488
+ TallyMap.updateBalance(receiverAddress,3,liqRewardBaseline2,0,0,0,'baselineLiquidityReward')
489
+ }
490
+ if(isListedA){
491
+ const liqReward1= await VolumeIndex.calculateLiquidityReward(satsReceived,0)
492
+ TallyMap.updateBalance(senderAddress,3,liqReward1,0,0,0,'enhancedLiquidityReward')
493
+ }
494
+ if(isListedB){
495
+ const liqReward2= await VolumeIndex.calculateLiquidityReward(tokenAmount,propertyId)
496
+ TallyMap.updateBalance(receiverAddress,3,liqReward2,0,0,0,'enhancedLiquidityReward')
497
+
498
+ }
499
+ return
500
+ },
501
+ // commitToken: Commits tokens for a specific purpose
502
+ async commitToken(senderAddress, channelAddress, propertyId, tokenAmount, payEnabled, clearLists, block, txid) {
503
+
504
+ // Deduct tokens from sender's available balance
505
+ await TallyMap.updateBalance(senderAddress, propertyId, -tokenAmount, 0, 0, 0,'commit',block);
506
+
507
+ // Add tokens to the channel's balance
508
+ await TallyMap.updateChannelBalance(channelAddress, propertyId, tokenAmount,'channelReceive',block);
509
+ console.log('commiting tokens '+tokenAmount+' '+block+' '+txid)
510
+ // Determine which column (A or B) to assign the tokens in the channel registry
511
+ await Channels.recordCommitToChannel(channelAddress, senderAddress, propertyId, tokenAmount, payEnabled, clearLists, block, txid);
512
+
513
+ console.log(`Committed ${tokenAmount} tokens of propertyId ${propertyId} from ${senderAddress} to channel ${channelAddress}`);
514
+ return;
515
+ },
516
+
517
+ async onChainTokenToToken(fromAddress, offeredPropertyId, desiredPropertyId, amountOffered, amountExpected, txid, blockHeight, stop,post){
518
+ const pairKey = `${offeredPropertyId}-${desiredPropertyId}`;
519
+
520
+ const txInfo = await TxUtils.getRawTransaction(txid);
521
+ const confirmedBlock = await TxUtils.getBlockHeight(txInfo.blockhash);
522
+
523
+ if (stop === true && post === true) {
524
+ post = false;
525
+ }
526
+
527
+ const order = {
528
+ offeredPropertyId:offeredPropertyId,
529
+ desiredPropertyId:desiredPropertyId,
530
+ amountOffered:amountOffered,
531
+ amountExpected:amountExpected,
532
+ blockTime: confirmedBlock,
533
+ sender: fromAddress,
534
+ stop: stop,
535
+ post: post
536
+ };
537
+
538
+ console.log('queueing on-chain token order ' + JSON.stringify(order), txid);
539
+
540
+ // Do NOT mutate the book immediately; just enqueue
541
+ await Orderbook.queueOnChainTokenOrder(
542
+ pairKey,
543
+ fromAddress,
544
+ order,
545
+ blockHeight,
546
+ txid
547
+ );
548
+
549
+ return order;
550
+ },
551
+
552
+ async cancelOrder(fromAddress, isContract, offeredPropertyId, desiredPropertyId, cancelAll, cancelParams,block) {
553
+ let cancelledOrders = [];
554
+ let key
555
+ if(isContract==true){
556
+ key = offeredPropertyId
557
+ }else if(isContract==false){
558
+ key = offeredPropertyId+'-'+desiredPropertyId
559
+ }
560
+ let orderbook = new Orderbook(key)
561
+ // Handle contract cancellation if only one property ID is provided
562
+ console.log('in logic function for cancelOrder '+fromAddress + ' '+isContract +' '+offeredPropertyId+' '+desiredPropertyId +' '+cancelAll+ ' '+JSON.stringify(cancelParams))
563
+ if(isContract==true){
564
+ // Contract cancellation logic here
565
+ if(cancelAll){
566
+ cancelledOrders = await orderbook.cancelAllContractOrders(fromAddress,offeredPropertyId,block)
567
+ //console.log('contract cancel all'+JSON.stringify(cancelledOrders))
568
+ }
569
+ if(cancelParams.txid){
570
+ cancelledOrders = await orderbook.cancelContractOrderByTxid(fromAddress,offeredPropertyId,cancelParams.txid,block)
571
+ }
572
+ if(cancelParams.price){
573
+ if(cancelParams.buy){
574
+ cancelledOrders = await orderbook.cancelContractBuyOrdersByPrice(fromAddress,offeredPropertyId,cancelParams.price,cancelParams.buy,block)
575
+ }
576
+ if(cancelParams.sell){
577
+ cancelledOrders = await orderbook.cancelContractSellOrdersByPrice(fromAddress,offeredPropertyId,cancelParams.price,cancelParams.sell,block)
578
+ }
579
+ }
580
+ await orderbook.saveOrderBook(`${offeredPropertyId}`);
581
+ }
582
+
583
+ if(isContract==false){
584
+ //normalize the order of propertyIds
585
+
586
+ if (cancelAll && offeredPropertyId && desiredPropertyId) {
587
+ console.log('canceling all orders for '+fromAddress + offeredPropertyId+ desiredPropertyId)
588
+ cancelledOrders = await orderbook.cancelAllTokenOrders(fromAddress, offeredPropertyId, desiredPropertyId,block);
589
+ }
590
+ // Cancel a specific order by txid
591
+ if (cancelParams.txid) {
592
+ cancelledOrders = await orderbook.cancelTokenOrdersByTxid(fromAddress,offeredPropertyId,desiredPropertyId, cancelParams.txid,block);
593
+ }
594
+
595
+ // Cancel orders by price or order type
596
+ if (cancelParams.price || cancelParams.orderType) {
597
+ if (cancelParams.price) {
598
+ // Cancel sell orders greater than or equal to the price
599
+ cancelledOrders = await orderbook.cancelTokenSellOrdersByPrice(fromAddress, offeredPropertyId, desiredPropertyId, cancelParams.price,block);
600
+
601
+ // Cancel buy orders less than or equal to the price
602
+ cancelledOrders = await orderbook.cancelTokenBuyOrdersByPrice(fromAddress, offeredPropertyId, desiredPropertyId, cancelParams.price,block);
603
+ }
604
+ // Add more conditions based on your cancel params if needed
605
+ }
606
+
607
+ // Save the updated order book to the database
608
+ await orderbook.saveOrderBook(`${offeredPropertyId}-${desiredPropertyId}`);
609
+ }
610
+
611
+ // Log the cancellation for record-keeping
612
+ //console.log(`Cancelled orders: ${JSON.stringify(cancelledOrders)}`);
613
+
614
+ // Return the details of the cancelled orders
615
+ return cancelledOrders;
616
+ },
617
+ /**
618
+ * Creates a new clearlist.
619
+ *
620
+ * @param {Object} params - Parameters for creating the clearlist
621
+ * @param {string} params.adminAddress - The address of the admin for this clearlist
622
+ * @param {string} [params.name] - Optional name for the clearlist
623
+ * @param {Array} [params.criteria] - Optional criteria for inclusion in the clearlist
624
+ * @param {string} [params.backupAddress] - Optional backup address for admin operations
625
+ * @returns {Object} - The result of the clearlist creation
626
+ */
627
+ async createClearList(adminAddress, name, url, description, backupAddress, block){
628
+
629
+ // Validate input parameters
630
+ if (!adminAddress) {
631
+ return console.log('Admin address is required to create a clearlist');
632
+ }
633
+
634
+ // Create the clearlist
635
+ const clearlistData = await ClearList.createclearlist({
636
+ adminAddress,
637
+ name,
638
+ url,
639
+ description,
640
+ backupAddress
641
+ });
642
+
643
+ // Return a message with the new clearlist ID
644
+ return {
645
+ message: `clearlist created successfully with ID: ${clearlistData.id}`
646
+ };
647
+ },
648
+
649
+ async updateAdmin(whitelist,token,oracle, newAddress, id, updateBackup, block) {
650
+
651
+ if(whitelist){
652
+ await ClearList.updateAdmin(id, newAddress,updateBackup);
653
+ }else if(token){
654
+ await PropertyList.updateAdmin(id, newAddress,updateBackup);
655
+ }else if(oracle){
656
+ await OracleList.updateAdmin(entityId, newAddress, updateBackup);
657
+ }
658
+
659
+ console.log(`Admin updated for ${entityType} ${entityId}`);
660
+ return
661
+ },
662
+
663
+
664
+ async issueOrRevokeAttestation(sender, clearlistId, targetAddress, metaData, revoke, block) {
665
+ const admin = activation.getAdmin()
666
+ if(sender==admin&&clearlistId==0){
667
+ console.log('admin updating banlist')
668
+ await updateBannedCountries(metaData,block)
669
+ return
670
+ }
671
+ if(!revoke){
672
+ console.log('params in add attest '+clearlistId,targetAddress,metaData,revoke,block)
673
+ await ClearList.addAttestation(clearlistId, targetAddress,metaData, block);
674
+ console.log(`Address ${targetAddress} added to clearlist ${clearlistId}`);
675
+ }else if(revoke==true){
676
+ await ClearList.revokeAttestation(clearlistId,targetAddress,metaData, block)
677
+ }
678
+ return
679
+ },
680
+
681
+ async updateBannedCountries(bannedCountriesGlobal, block) {
682
+ // Validate input: Must be an array of two-character strings
683
+ if (!Array.isArray(bannedCountriesGlobal) || !bannedCountriesGlobal.every(code => typeof code === 'string' && code.length === 2)) {
684
+ return console.log('Invalid input: bannedCountriesGlobal must be an array of two-character strings.');
685
+ }
686
+
687
+ console.log('Using default global Banlist:', bannedCountriesGlobal);
688
+ await Clearlist.setBanList(bannedCountriesGlobal,block); // Update Clearlist object with default
689
+ },
690
+
691
+
692
+ async AMMPool(sender, block, isRedeem, isContract, id, amount, id2, amount2) {
693
+ let ammInstance;
694
+
695
+ if (isContract) {
696
+ ammInstance = await ContractRegistry.getAMM(id);
697
+ } else {
698
+ ammInstance = await PropertyRegistry.getAMM(id, id2);
699
+ }
700
+
701
+ if (!ammInstance) {
702
+ throw new Error('AMM instance not found');
703
+ }
704
+
705
+ if (isRedeem&&isContract) {
706
+ await ammInstance.redeemCapital(sender, id, amount, isContract, block);
707
+ }else if(isRedeem&&!isContract){
708
+ await ammInstance.redeemCapital(sender, id, amount, isContract, id2, amount2, block)
709
+ }else if(!isRedeem&&isContract){
710
+ await ammInstance.addCapital(sender, id, amount, isContract, block);
711
+ }else if(!isRedeem&&!isContract){
712
+ await ammInstance.addCapital(sender, id, amount,isContract, id2, amount2,block)
713
+ }
714
+ },
715
+
716
+ async grantManagedToken(propertyId, amount, recipientAddress, propertyManager,block) {
717
+
718
+ // Verify if the property is a managed type
719
+ const isManaged = await propertyManager.verifyIfManaged(propertyId);
720
+ if (!isManaged) {
721
+ throw new Error('Property is not a managed type');
722
+ }
723
+
724
+ // Logic to grant tokens to the recipient
725
+ await PropertyManager.grantTokens(propertyId, recipientAddress, amount,block);
726
+ console.log(`Granted ${amount} tokens of property ${propertyId} to ${recipientAddress}`);
727
+ return
728
+ },
729
+
730
+ async redeemManagedToken(propertyId, amount, address,block) {
731
+
732
+ // Verify if the property is a managed type
733
+ const isManaged = await propertyManager.verifyIfManaged(propertyId);
734
+ if (!isManaged) {
735
+ throw new Error('Property is not a managed type');
736
+ }
737
+
738
+ // Logic to redeem tokens from the admin's balance
739
+ await PropertyManager.redeemTokens(address, propertyId, amount,block);
740
+ console.log(`Redeemed ${amount} tokens of property ${propertyId}`);
741
+ return
742
+ },
743
+
744
+ async createOracle(adminAddress, ticker, url, backupAddress, clearlists, lag, oracleRegistry,block) {
745
+
746
+ // Create a new oracle
747
+ const oracleId = await OracleList.createOracle({adminAddress, ticker, url, backupAddress, clearlists, lag});
748
+ console.log(`Oracle created with ID: ${oracleId}`);
749
+ return oracleId;
750
+ },
751
+
752
+ async publishOracleData(oracleId, price, high, low, close, block) {
753
+ console.log('publishing Oracle Data '+oracleId + ' '+ price)
754
+ // Publish data to the oracle
755
+ await OracleList.publishData(oracleId, price, high, low, close, block);
756
+ console.log(`Data published to oracle ${oracleId}`);
757
+ return
758
+ },
759
+
760
+ async closeOracle(oracleId, block) {
761
+
762
+ // Close the specified oracle
763
+ await OracleList.closeOracle(oracleId);
764
+ console.log(`Oracle ${oracleId} has been closed`);
765
+ return
766
+ },
767
+
768
+ async createContractSeries(sender, native, underlyingOracleId, onChainData, notionalPropertyId, notionalValue, collateralPropertyId, leverage, expiryPeriod, series, inverse, fee, block, whitelist) {
769
+ // Create a new future contract series
770
+
771
+ const params = {
772
+ sender: sender,
773
+ native:native,
774
+ underlyingOracleId: underlyingOracleId,
775
+ onChainData: onChainData,
776
+ notionalPropertyId: notionalPropertyId,
777
+ notionalValue: notionalValue,
778
+ collateralPropertyId: collateralPropertyId,
779
+ leverage:leverage,
780
+ expiryPeriod: expiryPeriod,
781
+ series:series,
782
+ inverse: inverse,
783
+ fee: fee,
784
+ block: block,
785
+ whitelist:whitelist
786
+ }
787
+
788
+ const futureContractSeriesId = await ContractRegistry.createContractSeries(
789
+ sender, params, block
790
+ );
791
+ console.log(`Future contract series created with ID: ${futureContractSeriesId}`);
792
+ return futureContractSeriesId;
793
+ },
794
+
795
+ async exerciseDerivative(contractId, amount, contractsRegistry,block) {
796
+ if (!contractId || !amount || !contractsRegistry) {
797
+ throw new Error('Missing required parameters');
798
+ }
799
+
800
+ // Exercise the derivative contract
801
+ await ContractRegistry.exerciseDerivative(contractId, amount);
802
+ console.log(`Derivative contract ${contractId} exercised for amount ${amount}`);
803
+ },
804
+
805
+ async tradeContractOnchain(contractId, price, amount, sell, insurance, blockTime, txid, sender, isLiq, reduce, post, stop) {
806
+ const params = {
807
+ contractId,
808
+ price,
809
+ amount,
810
+ sell,
811
+ insurance,
812
+ blockTime,
813
+ isLiq,
814
+ reduce,
815
+ post,
816
+ stop
817
+ };
818
+
819
+ console.log('queueing on-chain contract order ' + JSON.stringify(params), txid);
820
+
821
+ // Again: no immediate addContractOrder; just enqueue
822
+ await Orderbook.queueOnChainContractOrder(
823
+ contractId,
824
+ sender,
825
+ params,
826
+ blockTime, // if you want strict height, pass blockHeight instead
827
+ txid
828
+ );
829
+
830
+ return;
831
+ },
832
+
833
+ async tradeContractChannel(
834
+ contractId,
835
+ price,
836
+ amount,
837
+ columnAIsSeller,
838
+ expiryBlock,
839
+ insurance,
840
+ channelAddress,
841
+ block,
842
+ txid,
843
+ columnAIsMaker
844
+ ) {
845
+ const { commitAddressA, commitAddressB } = await Channels.getCommitAddresses(channelAddress);
846
+ const orderbook = await Orderbook.getOrderbookInstance(contractId);
847
+
848
+ const initMarginPerContract = await ContractRegistry.getInitialMargin(contractId, price);
849
+ const initMarginBN = new BigNumber(initMarginPerContract);
850
+ const amountBN = new BigNumber(amount);
851
+ const marginUsed = amountBN.times(initMarginBN).toNumber();
852
+ let buyerAddress, sellerAddress;
853
+ if (columnAIsSeller) {
854
+ sellerAddress = commitAddressA;
855
+ buyerAddress = commitAddressB;
856
+ } else {
857
+ sellerAddress = commitAddressB;
858
+ buyerAddress = commitAddressA;
859
+ }
860
+
861
+ const isInverse = ContractRegistry.isInverse(contractId);
862
+
863
+ // Figure out maker/taker roles based on columnAIsMaker
864
+ const sellerMaker = columnAIsSeller ? !!columnAIsMaker : !columnAIsMaker;
865
+ const buyerMaker = columnAIsSeller ? !columnAIsMaker : !!columnAIsMaker;
866
+
867
+ console.log('flags in trade logic '+sellerMaker+' '+buyerMaker+' '+columnAIsSeller+' '+columnAIsMaker)
868
+
869
+ const sellOrder = {
870
+ contractId,
871
+ amount,
872
+ price,
873
+ block,
874
+ sellSide: true,
875
+ marginUsed,
876
+ sellerAddress,
877
+ txid,
878
+ maker: sellerMaker // ← attach flag
879
+ };
880
+
881
+ const buyOrder = {
882
+ contractId,
883
+ amount,
884
+ price,
885
+ block,
886
+ buySide: true,
887
+ marginUsed,
888
+ buyerAddress,
889
+ txid,
890
+ maker: buyerMaker // ← attach flag
891
+ };
892
+
893
+ const match = {
894
+ sellOrder,
895
+ buyOrder,
896
+ price,
897
+ channelAddress,
898
+ tradePrice: price,
899
+ txid
900
+ };
901
+
902
+ const matches = [match];
903
+
904
+ // Trade the contract within a channel
905
+ await orderbook.processContractMatches(matches, block, true);
906
+
907
+ console.log(
908
+ `Traded contract ${contractId} in channel with price ${price} and amount ${amount}. SellerMaker=${sellerMaker}, BuyerMaker=${buyerMaker}`
909
+ );
910
+
911
+ return;
912
+ },
913
+
914
+ async tradeTokensChannel(
915
+ offeredPropertyId,
916
+ desiredPropertyId,
917
+ amountOffered,
918
+ amountDesired,
919
+ expiryBlock,
920
+ columnAIsOfferer, // true if Column A is the one offering
921
+ channelAddress,
922
+ block,
923
+ txid,
924
+ columnAIsMaker // new param: true if Column A was the maker
925
+ ) {
926
+ const { commitAddressA, commitAddressB } = await Channels.getCommitAddresses(channelAddress);
927
+ console.log('inside tokens channel', commitAddressA, commitAddressB, 'channel addr', channelAddress);
928
+
929
+ const key = `${offeredPropertyId}-${desiredPropertyId}`;
930
+ const orderbook = await Orderbook.getOrderbookInstance(key);
931
+
932
+ let buyerAddress, sellerAddress;
933
+ if (columnAIsOfferer) {
934
+ sellerAddress = commitAddressA;
935
+ buyerAddress = commitAddressB;
936
+ } else {
937
+ sellerAddress = commitAddressB;
938
+ buyerAddress = commitAddressA;
939
+ }
940
+
941
+ // Maker assignment
942
+ const sellerMaker = columnAIsOfferer && columnAIsMaker;
943
+ const buyerMaker = !columnAIsOfferer && columnAIsMaker;
944
+
945
+ const sellOrder = {
946
+ offeredPropertyId,
947
+ desiredPropertyId,
948
+ amountOffered,
949
+ amountExpected: amountDesired,
950
+ blockTime: block,
951
+ sender: sellerAddress,
952
+ maker: sellerMaker // attach maker flag
953
+ };
954
+
955
+ const buyOrder = {
956
+ offeredPropertyId,
957
+ desiredPropertyId,
958
+ amountOffered: amountDesired,
959
+ amountExpected: amountOffered,
960
+ blockTime: block,
961
+ sender: buyerAddress,
962
+ maker: buyerMaker // attach maker flag
963
+ };
964
+
965
+ const amountOfferedBN = new BigNumber(amountOffered);
966
+ const amountDesiredBN = new BigNumber(amountDesired);
967
+
968
+ const tradePrice = amountOfferedBN.dividedBy(amountDesiredBN);
969
+
970
+ const match = {
971
+ sellOrder,
972
+ buyOrder,
973
+ amountOfTokenA: amountOfferedBN.toNumber(),
974
+ amountOfTokenB: amountDesiredBN.toNumber(),
975
+ tradePrice: tradePrice.toNumber(),
976
+ channel: channelAddress,
977
+ buyerTx: txid,
978
+ sellerTx: txid
979
+ };
980
+
981
+ const matches = [match];
982
+
983
+ // Update balances in the channel columns and commitment addresses
984
+ console.log('about to process token match in channel', JSON.stringify(matches), block);
985
+ await orderbook.processTokenMatches(matches, block, txid, true);
986
+
987
+ const ltcValueOfToken = VolumeIndex.getTokenPriceInLTC(desiredPropertyId);
988
+ const ltcValueOfTokens = new BigNumber(ltcValueOfToken)
989
+ .times(amountDesiredBN)
990
+ .decimalPlaces(8)
991
+ .toNumber();
992
+
993
+ await VolumeIndex.saveVolumeDataById(
994
+ key,
995
+ amountOffered,
996
+ ltcValueOfTokens,
997
+ tradePrice,
998
+ block,
999
+ 'token'
1000
+ );
1001
+
1002
+ return `Trade executed in channel ${channelAddress}`;
1003
+ },
1004
+
1005
+
1006
+ withdrawal(withdrawAll, channelAddress, propertyId, amount, sender, block, columnIsB) {
1007
+ const channel = Channels.getChannel(channelAddress);
1008
+ // Assuming channel object has a map of property balances
1009
+ Channels.addToWithdrawalQueue(block, sender, amount, channelAddress,propertyId, withdrawAll, columnIsB)
1010
+ return
1011
+ },
1012
+
1013
+ async transfer(fromChannelAddress, toChannelAddress, propertyId, amount, isColumnA, pay, payRefAddress, block,txid) {
1014
+ let fromChannel = await Channels.getChannel(fromChannelAddress);
1015
+
1016
+ console.log(`To channel ${toChannelAddress} not found. Adding to registry.`);
1017
+ await Channels.recordCommitToChannel(toChannelAddress, fromChannelAddress, propertyId, amount, false, '', block,txid);
1018
+ let toChannel = await Channels.getChannel(toChannelAddress);
1019
+ console.log(JSON.stringify(toChannel))
1020
+ // Determine the correct column to deduct from in the fromChannel
1021
+ const fromColumn = isColumnA ? 'A' : 'B';
1022
+ let channelColumn = ' '
1023
+ if(toChannel.participants.A==fromChannel.participants[fromColumn]){
1024
+ channelColumn = 'A'
1025
+ }else if (toChannel.participants.B==fromChannel.participants[fromColumn]){
1026
+ channelColumn = 'B'
1027
+ }
1028
+ // Check if the fromChannel has enough balance
1029
+
1030
+ // Assign columns in the toChannel based on the address
1031
+ //await Channels.assignColumnBasedOnAddress(toChannelAddress, toChannelAddress);
1032
+
1033
+ // Update balances in from channel
1034
+ fromChannel[fromColumn][propertyId] -= amount;
1035
+ // Assign the commit address based on pay status
1036
+ if (pay && payRefAddress) {
1037
+ // If pay is true and payRefAddress is provided, set it as the commit address
1038
+ toChannel.participants[channelColumn] = payRefAddress;
1039
+ console.log(`Setting commit address in toChannel ${channelColumn} as payRefAddress: ${payRefAddress}`);
1040
+ } else {
1041
+ // Otherwise, use the fromChannel's participant address
1042
+ const senderCommitAddress = fromChannel.participants[fromColumn];
1043
+ toChannel.participants[channelColumn] = senderCommitAddress;
1044
+ console.log(`Setting commit address in toChannel ${channelColumn} as fromChannel participant address: ${senderCommitAddress}`);
1045
+ }
1046
+
1047
+ TallyMap.updateChannelBalance(fromChannelAddress, propertyId, -amount,'transferDebit', block)
1048
+ TallyMap.updateChannelBalance(toChannelAddress, propertyId, amount, 'transferCredit', block)
1049
+
1050
+ // Save updated channel states back to the registry
1051
+ Channels.channelsRegistry.set(fromChannelAddress, fromChannel);
1052
+
1053
+ await Channels.saveChannelsRegistry();
1054
+ return
1055
+ },
1056
+
1057
+ async settleChannelPNL(channelAddress, txParams, block,txid) {
1058
+ const {
1059
+ txidNeutralized1,
1060
+ txidNeutralized2,
1061
+ markPrice,
1062
+ close
1063
+ } = txParams;
1064
+
1065
+ if(txidNeutralized2){
1066
+ const settlement = await Scaling.nuetralizeSettlement(channel,txidNeutralized2)
1067
+ }
1068
+
1069
+ const trade = await Scaling.isTradePublished(txidNeutralized1)
1070
+ let offset
1071
+ if(trade.status=="unpublished"){
1072
+ await Scaling.settlementLimbo(txid) //Must check settlement limbo for references in logic of channel trades
1073
+ }else if(trade.status=="expiredContract"){
1074
+ await Logic.typeSwitch(19,trade.params)
1075
+ }else if(trade.status=="expiredToken"){
1076
+ await Logic.typeSwitch(20,trade.params)
1077
+ }else if((trade.status=="liveContract"||trade.status=="expiredContract")&&close==true){
1078
+ offset = Scaling.generateOffset(trade.params,markPrice)
1079
+ await Logic.typeSwitch(19,offset.params)
1080
+ }else if((trade.status=="liveContract"||trade.status=="expiredContract")&&close==true){
1081
+ offset = Scaling.generateOffset(trade.params,markPrice)
1082
+ await Logic.typeSwitch(20,offset.params)
1083
+ }else if(trade.status=="live"&&!close){
1084
+ const last = await Scaling.queryPriorSettlements(txidNuetralized1, txidNeutralized2, channelAddress)
1085
+ const settlement = await Scaling.settlePNL(last,mark,txidNuetralized1)
1086
+ }
1087
+
1088
+ console.log(`PNL settled for channel ${channelAddress}, contract ${contractId}`);
1089
+ return
1090
+ },
1091
+
1092
+ exerciseDerivative(sender, txParams,block) {
1093
+ const { contractId, amount } = txParams;
1094
+
1095
+ // Check if the contractId has more hyphens and contains 'P' or 'C'
1096
+ const hyphenCount = (contractId.match(/-/g) || []).length;
1097
+ const hasPOrC = /[PC]/.test(contractId);
1098
+ const isOption = Boolean(hyphenCount >= 2 && hasPOrC);
1099
+ const marginMap = MarginMap.getInstance(contractId)
1100
+ if(!isOption){
1101
+ this.deliverContract(sender, contractId, amount,block);
1102
+ }else if(isOption){
1103
+ this.handleOptionExercise(sender,contractId, amount,block);
1104
+ }
1105
+ },
1106
+
1107
+
1108
+ deliverContract(contractId, amount,block) {
1109
+ // Logic for contract delivery
1110
+ // This would involve transferring tokens from the contract to the exercising party
1111
+ // Eliminate the contract positions
1112
+
1113
+ // Retrieve contract details and involved parties' balances
1114
+ // Assume existence of functions getContractDetails and getAddressBalance
1115
+ const contractDetails = ContractRegistry.getContractDetails(contractId);
1116
+ const senderBalance = this.getAddressBalance(contractDetails.senderAddress, propertyId);
1117
+ const receiverBalance = this.getAddressBalance(contractDetails.receiverAddress, propertyId);
1118
+
1119
+ // Transfer tokens based on contract terms
1120
+ if (senderBalance >= amount) {
1121
+ this.updateBalance(contractDetails.senderAddress, propertyId, -amount, 0 ,0,0,'deliver');
1122
+ this.updateBalance(contractDetails.receiverAddress, propertyId, amount,0,0,0,'receiveExercise');
1123
+ } else {
1124
+ throw new Error('Insufficient balance for contract delivery');
1125
+ }
1126
+
1127
+ // Eliminate the contract
1128
+ this.removeContract(contractId);
1129
+ },
1130
+
1131
+ handleOptionExercise(contractId, propertyId1, propertyId2, numberOfContracts, block) {
1132
+ // Logic for handling option exercise
1133
+ // Notional value of the contract is based on the strike price
1134
+ // Eliminate the contract positions
1135
+
1136
+ // Retrieve contract details
1137
+ const contractDetails = this.getContractDetails(contractId);
1138
+ const strikePrice = contractDetails.strikePrice; // The strike price of the option
1139
+
1140
+ // Calculate the notional value based on the strike price
1141
+ const notionalValue = numberOfContracts * strikePrice;
1142
+
1143
+ // Retrieve balances of involved parties
1144
+ const balanceProperty1 = this.getAddressBalance(contractDetails.holderAddress, propertyId1);
1145
+ const balanceProperty2 = this.getAddressBalance(contractDetails.writerAddress, propertyId2);
1146
+
1147
+ // Execute the exchange if balances are sufficient
1148
+ if (balanceProperty1 >= notionalValue && balanceProperty2 >= numberOfContracts) {
1149
+ // Holder of the option (buyer) exercises the option
1150
+ this.updateBalance(contractDetails.holderAddress, propertyId1, -notionalValue);
1151
+ this.updateBalance(contractDetails.holderAddress, propertyId2, numberOfContracts);
1152
+
1153
+ // Writer of the option (seller) fulfills the option
1154
+ this.updateBalance(contractDetails.writerAddress, propertyId1, notionalValue);
1155
+ this.updateBalance(contractDetails.writerAddress, propertyId2, -numberOfContracts);
1156
+ } else {
1157
+ throw new Error('Insufficient balance for option exercise');
1158
+ }
1159
+
1160
+ // Eliminate the contract
1161
+ this.removeContract(contractId);
1162
+ },
1163
+
1164
+
1165
+ // Mint Synthetic execution
1166
+ async mintSynthetic(address, propertyId, contractId, amount, block, grossRequired, contracts, margin) {
1167
+ const syntheticTokenId = `s-${propertyId}-${contractId}`;
1168
+ const propertyManager = PropertyManager.getInstance();
1169
+
1170
+ // Clamp values symmetrically
1171
+ amount = BigNumber(Math.abs(amount)).decimalPlaces(8, BigNumber.ROUND_DOWN).toNumber(); // minted synth
1172
+ margin = BigNumber(Math.abs(margin)).decimalPlaces(8, BigNumber.ROUND_DOWN).toNumber(); // credited margin
1173
+
1174
+ const marginMap = await MarginMap.getInstance(contractId);
1175
+ let propertyInfo = await PropertyManager.getPropertyData(propertyId);
1176
+ let ticker = propertyInfo.ticker;
1177
+ let synthTicker = 's' + ticker + '-' + contractId;
1178
+ const contractInfo = await ContractRegistry.getContractInfo(contractId);
1179
+
1180
+ await propertyManager.addProperty(
1181
+ syntheticTokenId,
1182
+ synthTicker,
1183
+ amount,
1184
+ 'Synthetic',
1185
+ contractInfo.whitelist,
1186
+ syntheticTokenId,
1187
+ null
1188
+ );
1189
+
1190
+ let contractsAndMargin = await marginMap.moveMarginAndContractsForMint(
1191
+ address,
1192
+ propertyId,
1193
+ contractId,
1194
+ contracts,
1195
+ margin,
1196
+ block
1197
+ );
1198
+
1199
+ grossRequired = BigNumber(grossRequired)
1200
+ .plus(contractsAndMargin.excess)
1201
+ .decimalPlaces(8, BigNumber.ROUND_UP) // debit side
1202
+ .toNumber();
1203
+
1204
+ await TallyMap.updateBalance(
1205
+ address,
1206
+ syntheticTokenId,
1207
+ BigNumber(amount).decimalPlaces(8, BigNumber.ROUND_DOWN).toNumber(), // credit side
1208
+ 0,0,0,'issueSynth',block
1209
+ );
1210
+
1211
+ await TallyMap.updateBalance(
1212
+ address,
1213
+ propertyId,
1214
+ BigNumber(-grossRequired).decimalPlaces(8, BigNumber.ROUND_UP).toNumber(), // debit side
1215
+ 0,
1216
+ BigNumber(-contractsAndMargin.margin).decimalPlaces(8, BigNumber.ROUND_UP).toNumber(), // debit side
1217
+ 0,
1218
+ 'issueSynth',block
1219
+ );
1220
+
1221
+ let exists = await SynthRegistry.exists(syntheticTokenId);
1222
+
1223
+ if (!exists) {
1224
+ console.log('creating new synth ' + syntheticTokenId);
1225
+ await SynthRegistry.createVault(propertyId, contractId);
1226
+ await SynthRegistry.registerSyntheticToken(syntheticTokenId, contractId, propertyId);
1227
+ console.log('about to update new vault ' + syntheticTokenId + ' ' + contractsAndMargin + ' ' + amount);
1228
+ await SynthRegistry.updateVault(syntheticTokenId, contractsAndMargin, amount, grossRequired);
1229
+ } else {
1230
+ console.log('about to update existing vault ' + syntheticTokenId + ' ' + contractsAndMargin + ' ' + amount);
1231
+ await SynthRegistry.updateVault(syntheticTokenId, contractsAndMargin, amount, grossRequired);
1232
+ }
1233
+
1234
+ console.log(`Minted ${amount} of synthetic token ${syntheticTokenId}`);
1235
+ return;
1236
+ },
1237
+
1238
+ async redeemSynthetic(address, propertyId, contractId, amount,block) {
1239
+
1240
+ // Split the string by hyphens
1241
+ const parts = propertyId.split('-');
1242
+
1243
+ // The middle part (index 1) is the collateral property
1244
+ const collateralProperty = parseInt(parts[1], 10);
1245
+
1246
+ // Redeem the synthetic token
1247
+ const vault = await SynthRegistry.getVault(propertyId);
1248
+ console.log('inside redeem synthetic logic '+vault.outstanding+' '+JSON.stringify(vault))
1249
+ if (!vault) {
1250
+ console.log('no vault found')
1251
+ return Error('Synthetic token vault not found');
1252
+ }
1253
+
1254
+ if (vault.outstanding < amount) {
1255
+ console.log('vault shortfall')
1256
+ throw new Error('Insufficient synthetic token balance for redemption');
1257
+ }
1258
+
1259
+ const marginMap = await MarginMap.getInstance(contractId)
1260
+ const contractInfo = await ContractRegistry.getContractInfo(contractId)
1261
+ let mark = 0
1262
+ if(contractInfo.native){
1263
+ let pair = contractInfo.onChainData[0][0]+"-"+contractInfo.onChainData[0][1]
1264
+ mark = await VolumeIndex.getLastPrice(pair,block)
1265
+ }else{
1266
+ mark = OracleList.getOraclePrice(contractInfo.underlyingOracleId)
1267
+ }
1268
+ const initMarginPerContract= await ContractRegistry.getInitialMargin(contractId, mark)
1269
+
1270
+ const notionalValue = contractInfo.notionalValue
1271
+ let contractsAndMargin = await marginMap.moveMarginAndContractsForRedeem(address, propertyId, contractId, amount,vault,notionalValue,initMarginPerContract,mark)
1272
+
1273
+ // Update synthetic token property
1274
+ await PropertyManager.updateTotalInCirculation(propertyId, -amount);
1275
+ await TallyMap.updateBalance(address, propertyId,-amount,0,0,0,'redeemSynth',block)
1276
+ await TallyMap.updateBalance(address, collateralProperty,contractsAndMargin.available,0,contractsAndMargin.margin,0,'redeemSynth',block)
1277
+
1278
+ if(contractsAndMargin.rPNL!=0){
1279
+ await TallyMap.updateBalance(address, collateralProperty, contractsAndMargin.rPNL, 0, 0, 0, 'closingLongsWithRedemption',block)
1280
+ }
1281
+
1282
+ if(contractsAndMargin.reduction!=0){
1283
+ await TallyMap.updateBalance(address, collateralProperty, contractsAndMargin.reduction, 0, -contractsAndMargin.reduction, 0, 'contractRedeemMarginReturn',block)
1284
+ }
1285
+ console.log('contracts and Margin before update Vault '+JSON.stringify(contractsAndMargin))
1286
+ await SynthRegistry.updateVaultRedeem(propertyId, contractsAndMargin,-amount);
1287
+
1288
+
1289
+ // Log the redemption of the synthetic token
1290
+ console.log(`Redeemed ${amount} of synthetic token ${propertyId}`);
1291
+ return
1292
+ },
1293
+
1294
+ // payToTokens: Distributes propertyIdUsed tokens to holders of propertyIdTarget tokens
1295
+ async payToTokens(propertyIdTarget, propertyIdUsed, amount,address,block) {
1296
+ // Check if enough tokens of propertyIdUsed are available for distribution
1297
+ const totalAvailable = tallyMap.totalTokens(propertyIdUsed);
1298
+ if (totalAvailable < amount) {
1299
+ throw new Error('Insufficient tokens for distribution');
1300
+ }
1301
+
1302
+ // Calculate total holdings of propertyIdTarget
1303
+ const totalHoldingTarget = tallyMap.totalTokens(propertyIdTarget);
1304
+ if (totalHoldingTarget <= 0) {
1305
+ throw new Error('No holders for target token');
1306
+ }
1307
+
1308
+ // Calculate and distribute tokens to each holder
1309
+ let remainingAmount = new BigNumber(amount);
1310
+ for (const [address, balances] of tallyMap.addresses.entries()) {
1311
+ const targetBalance = balances[propertyIdTarget];
1312
+ if (targetBalance && targetBalance.available > 0) {
1313
+ // Calculate the holder's share
1314
+ const share = new BigNumber(targetBalance.available).dividedBy(totalHoldingTarget);
1315
+ const payout = share.multipliedBy(amount);
1316
+
1317
+ // Distribute if the payout is significant (>= 0.00000001)
1318
+ if (payout.isGreaterThanOrEqualTo(new BigNumber('0.00000001'))) {
1319
+ // Update balances
1320
+ TallyMap.updateBalance(address, propertyIdUsed, -payout.toNumber(),0,0,0, 'payToTokens',block);
1321
+ remainingAmount = remainingAmount.minus(payout);
1322
+
1323
+ console.log(`Distributed ${payout.toFixed()} of token ${propertyIdUsed} to holder ${address}`);
1324
+ }
1325
+ }
1326
+ }
1327
+
1328
+ // Handle any remaining amount, possibly due to rounding
1329
+ if (!remainingAmount.isZero()) {
1330
+ // Choose a strategy to distribute the remaining amount
1331
+ // For example, add to a general pool, burn it, or send to a specific address
1332
+ // Example: send to a designated address
1333
+ const designatedAddress = 'some_designated_address';
1334
+ TallyMap.updateBalance(address, propertyIdUsed, remainingAmount.toNumber(),0,0,0,'payToTokensRounding',block);
1335
+ console.log(`Remaining ${remainingAmount.toFixed()} of token ${propertyIdUsed} sent to ${designatedAddress}`);
1336
+ }
1337
+
1338
+ // Save the updated state of the TallyMap
1339
+ await tallyMap.save(currentBlockHeight); // Replace currentBlockHeight with actual block height
1340
+ },
1341
+
1342
+ // inside logic.j
1343
+
1344
+ async processOptionTrade(sender, params, txid){
1345
+ // Validate first (also populates creditMargin, reduce/flip flags, rPNL, closed sizes)
1346
+ const res = await Validity.validateOptionTrade(sender, params, txid);
1347
+ if (!res.valid) return res;
1348
+
1349
+ const tMeta = OptionsEngine.parseTicker(params.contractId);
1350
+ const seriesInfo = await ContractRegistry.getContractInfo(tMeta.seriesId);
1351
+ const collateralPropertyId = seriesInfo.collateralPropertyId;
1352
+
1353
+ // Resolve commits
1354
+ const { commitAddressA, commitAddressB } = await Channels.getCommitAddresses(sender);
1355
+ const AIsSeller = (params.columnAIsSeller===true || params.columnAIsSeller===1 || params.columnAIsSeller==="1");
1356
+ const sellerAddr = AIsSeller ? commitAddressA : commitAddressB;
1357
+ const buyerAddr = AIsSeller ? commitAddressB : commitAddressA;
1358
+
1359
+ // 1) Premium transfer (buyer -> seller), if present
1360
+ if (Number(params.netPremium||0) !== 0) {
1361
+ const np = Number(params.netPremium);
1362
+ // buyer pays (available -)
1363
+ await TallyMap.updateBalance(
1364
+ buyerAddr, collateralPropertyId,
1365
+ -np, 0, 0, 0,
1366
+ 'optionPremiumPay', params.blockHeight, txid
1367
+ );
1368
+ // seller receives (available +)
1369
+ await TallyMap.updateBalance(
1370
+ sellerAddr, collateralPropertyId,
1371
+ +np, 0, 0, 0,
1372
+ 'optionPremiumReceive', params.blockHeight, txid
1373
+ );
1374
+ }
1375
+
1376
+ // 2) Margin moves on seller
1377
+ // - If reducing: free margin and realize PnL into available
1378
+ // - Else opening/adding: lock margin (available -> margin)
1379
+ const credit = Number(params.creditMargin || 0);
1380
+
1381
+ if (params.sellerReducing) {
1382
+ const r = Number(params.rpnlSeller || 0);
1383
+ await TallyMap.updateBalance(
1384
+ sellerAddr, collateralPropertyId,
1385
+ r, // availableChange (realized PnL)
1386
+ 0,
1387
+ -credit, // marginChange (unlock)
1388
+ 0,
1389
+ 'optionReduceSeller', params.blockHeight, txid
1390
+ );
1391
+ } else if (credit > 0) {
1392
+ await TallyMap.updateBalance(
1393
+ sellerAddr, collateralPropertyId,
1394
+ -credit, 0, +credit, 0,
1395
+ 'optionMarginLock', params.blockHeight, txid
1396
+ );
1397
+ }
1398
+
1399
+ // 3) Buyer reduce (rare but allowed if they were short and are buying to cover)
1400
+ if (params.buyerReducing) {
1401
+ const r = Number(params.rpnlBuyer || 0);
1402
+ // buyer realized PnL goes to available; if they had margin locked (short), also unlock proportional credit
1403
+ await TallyMap.updateBalance(
1404
+ buyerAddr, collateralPropertyId,
1405
+ r, 0, 0, 0, // we’re not adjusting buyer margin here (credit is seller’s requirement)
1406
+ 'optionReduceBuyer', params.blockHeight, txid
1407
+ );
1408
+ }
1409
+
1410
+ // 4) Record positions into margin map (hybrid, nested by ticker)
1411
+ const mm = await MarginMap.getInstance(tMeta.seriesId);
1412
+ await mm.applyOptionTrade(
1413
+ sellerAddr, // we write positions for both sides below
1414
+ params.contractId,
1415
+ -Math.abs(params.amount || 0), // seller delta negative (short if SELL)
1416
+ params.price,
1417
+ params.blockHeight,
1418
+ credit
1419
+ );
1420
+ await mm.applyOptionTrade(
1421
+ buyerAddr,
1422
+ params.contractId,
1423
+ +Math.abs(params.amount || 0), // buyer delta positive
1424
+ params.price,
1425
+ params.blockHeight,
1426
+ 0 // buyer doesn’t post credit margin in our model
1427
+ );
1428
+
1429
+ // 5) Combo leg: if it’s an option, do same; if it’s a perp/future, route to contract trade
1430
+ if (params.comboTicker && params.comboAmount) {
1431
+ const cMeta = OptionsEngine.parseTicker(params.comboTicker);
1432
+ if (cMeta && cMeta.type) {
1433
+ // Option combo leg: mirror deltas (typically opposite side)
1434
+ await mm.applyOptionTrade(
1435
+ sellerAddr,
1436
+ params.comboTicker,
1437
+ -(Math.abs(params.comboAmount||0)), // seller side consistent
1438
+ params.comboPrice || 0,
1439
+ params.blockHeight,
1440
+ 0 // margin included in credit for the package already
1441
+ );
1442
+ await mm.applyOptionTrade(
1443
+ buyerAddr,
1444
+ params.comboTicker,
1445
+ +(Math.abs(params.comboAmount||0)),
1446
+ params.comboPrice || 0,
1447
+ params.blockHeight,
1448
+ 0
1449
+ );
1450
+ } else {
1451
+ // Perp/future combo leg → use existing contract trade pathway
1452
+ await tradeContractChannel(sender, {
1453
+ contractId: params.comboTicker,
1454
+ amount: params.comboAmount,
1455
+ price: params.comboPrice || 0,
1456
+ columnAIsSeller: params.columnAIsSeller,
1457
+ expiryBlock: params.expiryBlock,
1458
+ isMaker: params.isMaker,
1459
+ blockHeight: params.blockHeight
1460
+ }, txid);
1461
+ }
1462
+ }
1463
+
1464
+ // 6) (Optional) Persist trade history w/ rPNL fields for auditing
1465
+ if (typeof TradeHistory?.recordTrade === 'function') {
1466
+ await TradeHistory.recordTrade(
1467
+ sellerAddr, params.contractId,
1468
+ -Math.abs(params.amount||0), params.price,
1469
+ Number(params.rpnlSeller||0),
1470
+ params.blockHeight, txid
1471
+ );
1472
+ await TradeHistory.recordTrade(
1473
+ buyerAddr, params.contractId,
1474
+ +Math.abs(params.amount||0), params.price,
1475
+ Number(params.rpnlBuyer||0),
1476
+ params.blockHeight, txid
1477
+ );
1478
+ }
1479
+
1480
+ return res;
1481
+ },
1482
+
1483
+ async tradeBaiUrbun(tallyMap, marginMap, channelRegistry, channelAddress, propertyIdDownPayment, propertyIdToBeSold, downPaymentPercentage, price, amount, expiryBlock, tradeExpiryBlock) {
1484
+ // Validate inputs and check balances
1485
+ if (!channelRegistry.hasChannel(channelAddress)) {
1486
+ throw new Error('Invalid channel address');
1487
+ }
1488
+
1489
+ const channel = channelRegistry.getChannel(channelAddress);
1490
+ const { committerA, committerB } = channel; // Assuming the channel has committerA and committerB
1491
+
1492
+ // Calculate down payment amount
1493
+ const downPaymentAmount = (downPaymentPercentage / 10000) * amount; // Convert basis points to actual amount
1494
+
1495
+ // Check if committers have enough balance for the trade
1496
+ if (!tallyMap.hasSufficientBalance(committerA, propertyIdToBeSold, amount)) {
1497
+ throw new Error('Seller (Committer A) has insufficient token balance for the property to be sold');
1498
+ }
1499
+ if (!tallyMap.hasSufficientBalance(committerB, propertyIdDownPayment, downPaymentAmount)) {
1500
+ throw new Error('Buyer (Committer B) has insufficient token balance for down payment');
1501
+ }
1502
+
1503
+ const baiUrbunContract = {
1504
+ type: 'BaiUrbun',
1505
+ propertyIdDownPayment,
1506
+ propertyIdToBeSold,
1507
+ downPaymentPercent,
1508
+ downPaymentAmount,
1509
+ totalAmount: amount,
1510
+ expiryBlock,
1511
+ tradeExpiryBlock,
1512
+ contractId: `B-${propertyIdToBeSold}-${propertyIdDownPayment}-${expiryBlock}`
1513
+ };
1514
+
1515
+ // Add the contract to the Bai Urbun registry
1516
+ await contractsRegistry.baiUrbun.addContract(baiUrbunContract);
1517
+
1518
+ // Generate contract ID for Bai Urbun
1519
+ const contractId = `B-${propertyIdToBeSold}-${propertyIdDownPayment}-${expiryBlock}`;
1520
+
1521
+ // Reserve the property and down payment in the tallyMap
1522
+ tallyMap.updateBalance(committerA, propertyIdToBeSold, -amount, 'available');
1523
+ tallyMap.updateBalance(committerA, propertyIdToBeSold, amount, 'reserved');
1524
+ tallyMap.updateBalance(committerB, propertyIdDownPayment, -downPaymentAmount, 'available');
1525
+ tallyMap.updateBalance(committerB, propertyIdDownPayment, downPaymentAmount, 'reserved');
1526
+
1527
+ // Update marginMap for Bai Urbun contract
1528
+ marginMap.updateContractBalance(committerA, contractId, amount, 'positive');
1529
+ marginMap.updateContractBalance(committerB, contractId, amount, 'negative');
1530
+
1531
+ console.log(`Created Bai Urbun contract with ID ${contractId} in channel ${channelAddress}`);
1532
+
1533
+ // Record the contract creation in the BaiUrbun registry
1534
+ // Additional logic to add the contract to the BaiUrbun registry
1535
+ // ...
1536
+
1537
+ return contractId;
1538
+ },
1539
+
1540
+
1541
+ tradeMurabaha(channelAddress, buyerAddress, sellerAddress, propertyId, costPrice, profitMargin, paymentBlockHeight) {
1542
+ // Check if the channel exists
1543
+ const channel = this.channelsRegistry.get(channelAddress);
1544
+ if (!channel) {
1545
+ throw new Error('Channel not found');
1546
+ }
1547
+
1548
+ // Validate addresses and amounts
1549
+ TxUtils.validateAddresses(buyerAddress, sellerAddress);
1550
+ TxUtils.validateAmounts(costPrice, profitMargin);
1551
+ // Example: Update margin at the time of agreement
1552
+ marginMap.updateMargin(buyerAddress, propertyId, -(costPrice + profitMargin)); // Buyer's margin decreases by total payment amount
1553
+ marginMap.updateMargin(sellerAddress, propertyId, costPrice); // Seller's margin increases by the cost price
1554
+
1555
+
1556
+ // Logic for Murabaha contract
1557
+ // Record the cost and profit margin
1558
+ channel.contracts.push({
1559
+ type: 'Murabaha',
1560
+ buyerAddress,
1561
+ sellerAddress,
1562
+ propertyId,
1563
+ costPrice,
1564
+ profitMargin,
1565
+ paymentBlockHeight
1566
+ });
1567
+
1568
+ console.log(`Murabaha contract created in channel ${channelAddress}`);
1569
+ },
1570
+
1571
+ issueInvoice(propertyManager, invoiceRegistry, propertyIdToReceivePayment, amount, dueDateBlock, propertyIdCollateral = null, receivesPayToToken = false, issuerNonce) {
1572
+ // Validate input parameters
1573
+ if (!propertyManager.isPropertyIdValid(propertyIdToReceivePayment)) {
1574
+ throw new Error('Invalid property ID to receive payment');
1575
+ }
1576
+ if (propertyIdCollateral && !propertyManager.isPropertyIdValid(propertyIdCollateral)) {
1577
+ throw new Error('Invalid property ID for collateral');
1578
+ }
1579
+
1580
+ // Generate an invoice ID
1581
+ const invoiceId = `${propertyIdToReceivePayment}-${dueDateBlock}-${issuerNonce}`;
1582
+
1583
+ // Create the invoice object
1584
+ const invoice = {
1585
+ invoiceId,
1586
+ propertyIdToReceivePayment,
1587
+ amount,
1588
+ dueDateBlock,
1589
+ collateral: propertyIdCollateral ? {
1590
+ propertyId: propertyIdCollateral,
1591
+ locked: receivesPayToToken,
1592
+ } : null,
1593
+ };
1594
+
1595
+ // Register the invoice in the invoice registry
1596
+ invoiceRegistry.registerInvoice(invoice);
1597
+
1598
+ console.log(`Invoice issued with ID: ${invoiceId}`);
1599
+
1600
+ // Optionally, if collateral is involved and receives payToToken, lock the collateral
1601
+ if (invoice.collateral && receivesPayToToken) {
1602
+ // Logic to lock collateral in association with this invoice
1603
+ // This might involve updating a collateral registry or similar system
1604
+ }
1605
+
1606
+ // Return the invoice ID for reference
1607
+ return invoiceId;
1608
+ },
1609
+
1610
+ batchMoveZkRollup(zkVerifier, rollupData, zkProof) {
1611
+ // Parse the Zero-Knowledge rollup data
1612
+ let transactions;
1613
+ try {
1614
+ transactions = JSON.parse(rollupData); // Assuming rollupData is a JSON string
1615
+ } catch (error) {
1616
+ throw new Error('Invalid rollup data format');
1617
+ }
1618
+
1619
+ // Validate the structure of the parsed data
1620
+ if (!isValidRollupDataStructure(transactions)) {
1621
+ throw new Error('Invalid rollup data structure');
1622
+ }
1623
+
1624
+ // Verify the Zero-Knowledge proof
1625
+ if (!zkVerifier.verify(zkProof, transactions)) {
1626
+ throw new Error('Invalid Zero-Knowledge proof');
1627
+ }
1628
+
1629
+ // Process each transaction in the batch
1630
+ transactions.forEach(transaction => {
1631
+ const { fromAddress, toAddress, propertyId, amount } = transaction;
1632
+
1633
+ // Perform necessary checks and balances updates for each transaction
1634
+ // For example, debiting from one address and crediting to another
1635
+ // This will involve interaction with a ledger or database
1636
+ });
1637
+
1638
+ console.log('Batched transactions processed successfully');
1639
+
1640
+ // Placeholder for additional proof logics to be parsed later
1641
+ // Implement as per the specific requirements of the rollup data and proofs
1642
+
1643
+ // Return success or a summary of the processed transactions
1644
+ return { status: 'success', transactionsProcessed: transactions.length };
1645
+ },
1646
+
1647
+ // Helper function to validate the structure of the rollup data
1648
+ isValidRollupDataStructure(transactions) {
1649
+ // Implement validation logic based on expected format
1650
+ // For example, checking for required fields in each transaction object
1651
+ return transactions.every(transaction =>
1652
+ transaction.hasOwnProperty('fromAddress') &&
1653
+ transaction.hasOwnProperty('toAddress') &&
1654
+ transaction.hasOwnProperty('propertyId') &&
1655
+ transaction.hasOwnProperty('amount')
1656
+ );
1657
+ },
1658
+
1659
+ batchSettlement(sender, params, txid, block){
1660
+
1661
+ },
1662
+
1663
+ publishNewTx(ordinalRevealJSON, jsCode) {
1664
+ // Validate the input JSON and JavaScript code
1665
+ if (!isValidJSON(ordinalRevealJSON)) {
1666
+ throw new Error('Invalid Ordinal Reveal JSON');
1667
+ }
1668
+ if (!isValidJavaScript(jsCode)) {
1669
+ throw new Error('Invalid JavaScript code');
1670
+ }
1671
+
1672
+ // Minify the JavaScript code (assuming a minification function exists)
1673
+ const minifiedJsCode = minifyJavaScript(jsCode);
1674
+
1675
+ // Assign a new transaction type ID
1676
+ const newTxTypeId = getNextTxTypeId();
1677
+
1678
+ // Construct the new transaction with the ordinal reveal JSON and minified JS code
1679
+ const newTx = {
1680
+ txTypeId: newTxTypeId,
1681
+ ordinalRevealJSON: ordinalRevealJSON,
1682
+ smartContractCode: minifiedJsCode
1683
+ };
1684
+
1685
+ // Save the new transaction to the system's registry
1686
+ // Assuming a function to save the transaction exists
1687
+ saveNewTransaction(newTx);
1688
+
1689
+ console.log(`Published new transaction type ID ${newTxTypeId}`);
1690
+
1691
+ // Return the new transaction type ID and details
1692
+ return { newTxTypeId, newTx };
1693
+ },
1694
+
1695
+ bindSmartContract(){},
1696
+
1697
+ mintColoredCoin(/* parameters */) { /* ... */ }
1698
+ };
1699
+
1700
+ module.exports = Logic;
1701
+
1702
+ // Example function to create and register a new token