@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,126 @@
1
+ // options.js
2
+ // Singleton helper for option tickers, reduce/flip bookkeeping, rPNL, and simple valuation.
3
+ // No state stored; singleton export for convenience.
4
+
5
+ class OptionsEngine {
6
+ // "series-expiry-(C|P)-strike?"
7
+ isOptionTicker(t) {
8
+ return typeof t === 'string' && /^.+?-\d+-(C|P)(-\d+(\.\d+)?)?$/.test(t);
9
+ }
10
+
11
+ parseTicker(t) {
12
+ if (!t || typeof t !== 'string') return null;
13
+ const parts = t.split('-');
14
+ if (parts.length < 3) return null;
15
+ const seriesId = parts[0];
16
+ const expiryBlock = parseInt(parts[1], 10);
17
+ const cp = parts[2];
18
+ const type = cp === 'C' ? 'Call' : (cp === 'P' ? 'Put' : null);
19
+ const strike = parts[3] ? parseFloat(parts[3]) : null;
20
+ if (!seriesId || Number.isNaN(expiryBlock) || !type) return null;
21
+ return { seriesId, expiryBlock, type, strike, raw: t };
22
+ }
23
+
24
+ /**
25
+ * Given existing signed qty and a signed delta, compute how much is closing vs flipping.
26
+ * existing >0 long, <0 short. delta >0 buy, <0 sell.
27
+ */
28
+ computeReduceFlip(existingQty, deltaQty) {
29
+ const ex = Number(existingQty) || 0;
30
+ const d = Number(deltaQty) || 0;
31
+ const after = ex + d;
32
+
33
+ const exSide = ex > 0 ? 'LONG' : ex < 0 ? 'SHORT' : null;
34
+ const dSide = d > 0 ? 'LONG' : d < 0 ? 'SHORT' : null;
35
+
36
+ let closedQty = 0;
37
+ let flipQty = 0;
38
+
39
+ if (ex !== 0 && d !== 0 && Math.sign(ex) !== Math.sign(d)) {
40
+ closedQty = Math.min(Math.abs(ex), Math.abs(d));
41
+ if (Math.abs(d) > Math.abs(ex)) {
42
+ flipQty = Math.abs(d) - Math.abs(ex);
43
+ }
44
+ }
45
+
46
+ const afterSide = after > 0 ? 'LONG' : after < 0 ? 'SHORT' : null;
47
+
48
+ return { existing: ex, delta: d, after, exSide, dSide, afterSide, closedQty, flipQty };
49
+ }
50
+
51
+ /**
52
+ * Realized PnL when reducing an option position.
53
+ * Long reduce: (trade - avg) * qty
54
+ * Short reduce: (avg - trade) * qty
55
+ */
56
+ rpnlForClose(exSide, closedQty, tradePrice, avgPrice) {
57
+ const q = Number(closedQty) || 0;
58
+ const p = Number(tradePrice) || 0;
59
+ const a = Number(avgPrice) || 0;
60
+ if (!q || !exSide) return 0;
61
+ return exSide === 'LONG' ? (p - a) * q : (a - p) * q;
62
+ }
63
+
64
+ /**
65
+ * Intrinsic value at spot S (European payoff at mark).
66
+ */
67
+ intrinsic(type, K, S) {
68
+ const k = Number(K) || 0;
69
+ const s = Number(S) || 0;
70
+ if (type === 'Call') return Math.max(0, s - k);
71
+ return Math.max(0, k - s);
72
+ }
73
+
74
+ /**
75
+ * Very light EU price proxy using Bachelier (normal) to avoid heavy math deps:
76
+ * price ≈ intrinsic + v * sqrt(T) * phi(0) (with a tiny convexity tweak)
77
+ * where v = vol (in price units), T in years.
78
+ * If you store a per-series vol index σ_annual (as decimal), you can use
79
+ * a Bachelier-like proxy with v = σ_annual * S for calls; puts symmetric.
80
+ * If vol is missing, fallback to intrinsic.
81
+ */
82
+ priceEUApprox(type, S, K, volAnnual, daysToExpiry) {
83
+ const s = Number(S) || 0;
84
+ const k = Number(K) || 0;
85
+ const T = Math.max(0, Number(daysToExpiry || 0)) / 365;
86
+ const iv = this.intrinsic(type, k, s);
87
+ if (!volAnnual || !T) return iv;
88
+
89
+ const sigma = Number(volAnnual); // if you store as decimal (e.g. 0.6)
90
+ const v = sigma * s; // price vol in Bachelier
91
+ const noise = v * Math.sqrt(T) * 0.3989; // ≈ φ(0) ~ 0.3989
92
+ // keep it conservative: intrinsic plus a slice of noise
93
+ return Math.max(iv, iv + noise);
94
+ }
95
+
96
+ /**
97
+ * Maintenance for *naked* shorts (10x leverage padding, your rule of thumb).
98
+ * Use strike/10 as generic notional for puts, and S/10 for calls (conservative).
99
+ * You can tune this per-series if you store policy on the registry.
100
+ */
101
+ nakedMaintenance(type, K, S) {
102
+ if (type === 'Call') return (Number(S) || 0) / 10; // ~10x leverage on spot notional
103
+ return (Number(K) || 0) / 10; // puts on strike notional
104
+ }
105
+
106
+ /**
107
+ * Mark-to-model exposure for a set of option positions (for liquidation offsets).
108
+ * positions: [{ type:'Call'|'Put', strike, qty (signed), avgPrice?, expiryBlock }]
109
+ * Returns total premium value (signed) at current S, using vol index and time.
110
+ */
111
+ mtmExposure(positions, S, volAnnual, blocksToExpiry, blocksPerDay) {
112
+ const bpd = Math.max(1, Number(blocksPerDay || 144)); // default ~ Bitcoin-like
113
+ const days = Math.max(0, Number(blocksToExpiry || 0) / bpd);
114
+ let prem = 0, intr = 0;
115
+ for (const p of (positions || [])) {
116
+ const price = this.priceEUApprox(p.type, S, p.strike, volAnnual, days);
117
+ prem += price * (Number(p.qty) || 0);
118
+ intr += this.intrinsic(p.type, p.strike, S) * (Number(p.qty) || 0);
119
+ }
120
+ return { premium: prem, intrinsic: intr };
121
+ }
122
+ }
123
+
124
+ // Export as a singleton instance.
125
+ const Options = new OptionsEngine();
126
+ module.exports = Options;
@@ -0,0 +1,394 @@
1
+ var db = require('./db')
2
+ var BigNumber = require('bignumber.js')
3
+ const Insurance = require('./insurance.js')
4
+
5
+ class OracleList {
6
+ static instance = null;
7
+ static lastOracleUpdateBlock = new Map();
8
+
9
+ constructor() {
10
+ if (!OracleList.instance) {
11
+ this.oracles = new Map(); // Initialize the oracles map only once
12
+ OracleList.instance = this;
13
+ }
14
+
15
+ return OracleList.instance;
16
+ }
17
+
18
+ static async getAllOracles() {
19
+ const instance = OracleList.getInstance();
20
+ await OracleList.load(); // Make sure the oracles are loaded
21
+
22
+ // Convert the Map of oracles to an array
23
+ return Array.from(instance.oracles.values());
24
+ }
25
+
26
+ async addOracle(oracleId, oracleData) {
27
+ try {
28
+ // Add to in-memory map
29
+ this.oracles.set(oracleId, oracleData);
30
+
31
+ // Add to NeDB database (if applicable)
32
+ const oracleDB = await db.getDatabase('oracleList');
33
+ await oracleDB.insertAsync({ _id: oracleId, ...oracleData });
34
+
35
+ console.log(`Oracle added: ID ${oracleId}`);
36
+ return true; // Indicate success
37
+ } catch (error) {
38
+ console.error(`Error adding oracle: ID ${oracleId}`, error);
39
+ throw error; // Re-throw the error for the caller to handle
40
+ }
41
+ }
42
+
43
+ static async getOracleInfo(oracleId) {
44
+ const instance = OracleList.getInstance();
45
+
46
+ // Check if in-memory map is empty and load if necessary
47
+ if (instance.oracles.size === 0) {
48
+ await OracleList.load();
49
+ }
50
+
51
+ // Oracle key to search for
52
+ const oracleKey = `oracle-${oracleId}`;
53
+
54
+ // Check in the in-memory map
55
+ const oracle = instance.oracles.get(oracleKey);
56
+ if (oracle) {
57
+ return oracle;
58
+ }
59
+
60
+ // If not found in-memory, optionally check the database
61
+ const oracleDB = await db.getDatabase('oracleList');
62
+ console.log('oracle key '+oracleKey)
63
+ const dbOracle = await oracleDB.findOneAsync({ _id: oracleKey });
64
+ console.log('db oracle '+ JSON.stringify(dbOracle))
65
+ if (dbOracle) {
66
+ return dbOracle;
67
+ }
68
+
69
+ console.log(`Oracle data not found for oracle ID: ${oracleId}`);
70
+ return null;
71
+ }
72
+
73
+ static async getOraclePrice(oracleId) {
74
+ // Prepare the query to find all entries with the specified oracleId
75
+ const oracleDB = await db.getDatabase('oracleData');
76
+ const oracleData = await oracleDB.findAsync({ oracleId: oracleId });
77
+
78
+ // Check if any data was returned
79
+ if (oracleData.length === 0) {
80
+ return 1
81
+ }
82
+
83
+ // Find the latest data point by blockHeight
84
+ const latestDataPoint = oracleData.reduce((latest, entry) => {
85
+ return (entry.blockHeight > latest.blockHeight) ? entry : latest;
86
+ });
87
+
88
+ console.log('Latest oracle data:', JSON.stringify(latestDataPoint));
89
+ return latestDataPoint.data.price;
90
+ }
91
+
92
+ static async publishData(oracleId, price, high, low, close, blockHeight) {
93
+ const lastBlock = OracleList.lastOracleUpdateBlock.get(oracleId);
94
+
95
+ if (lastBlock !== undefined && lastBlock >= blockHeight) {
96
+ console.log(`⛔ Oracle ${oracleId} already updated at block ${lastBlock}. Skipping block ${blockHeight}.`);
97
+ return;
98
+ }
99
+
100
+ // mark as updated
101
+ OracleList.lastOracleUpdateBlock.set(oracleId, blockHeight);
102
+
103
+ try {
104
+ const instance = OracleList.getInstance();
105
+
106
+ // Prepare oracle data
107
+ const oracleData = { price, high, low, close };
108
+ const lastPrice = await OracleList.getOraclePrice(oracleId)
109
+ console.log('last price '+lastPrice)
110
+ const priceBN = new BigNumber(price)
111
+ const lastPriceBN = new BigNumber(lastPrice)
112
+ const circuitLimitUp = new BigNumber(1.05).times(lastPriceBN).decimalPlaces(4).toNumber()
113
+ const circuitLimitDown = new BigNumber(0.95).times(lastPriceBN).decimalPlaces(4).toNumber()
114
+ console.log('price, limits '+price, lastPrice, circuitLimitDown, circuitLimitUp)
115
+ console.log('ergo, >limit up , <limit down' + Boolean(price>circuitLimitUp)+' '+Boolean(price<circuitLimitDown))
116
+ if(lastPrice!=1){
117
+ if(price>circuitLimitUp){
118
+ oracleData.price = circuitLimitUp
119
+ }else if(price <circuitLimitDown){
120
+ oracleData.price = circuitLimitDown
121
+ }
122
+ }
123
+ // Update in-memory oracle data (optional)
124
+ const oracleKey = `oracle-${oracleId}`;
125
+ instance.oracles.set(oracleKey, oracleData);
126
+
127
+ // Save oracle data to the database
128
+ await instance.saveOracleData(oracleId, oracleData, blockHeight);
129
+
130
+ console.log(`Data published to oracle ${oracleId} for block height ${blockHeight}`);
131
+ } catch (error) {
132
+ console.error(`Error publishing data to oracle ${oracleId} at block height ${blockHeight}:`, error);
133
+ throw error;
134
+ }
135
+ }
136
+
137
+ // Static method to get the singleton instance
138
+ static getInstance() {
139
+ if (!OracleList.instance) {
140
+ OracleList.instance = new OracleList();
141
+ }
142
+ return OracleList.instance;
143
+ }
144
+
145
+ static async load() {
146
+ try {
147
+ const oracleDB = await db.getDatabase('oracleList');
148
+ const oracles = await oracleDB.findAsync({});
149
+
150
+ const instance = OracleList.getInstance();
151
+ for (const oracle of oracles) {
152
+ instance.oracles.set(oracle._id, oracle);
153
+ }
154
+
155
+ console.log('Oracles loaded from the database');
156
+ } catch (error) {
157
+ console.error('Error loading oracles from the database:', error);
158
+ }
159
+ }
160
+
161
+ static async isAdmin(senderAddress, oracleId) {
162
+ try {
163
+ const oracleKey = `oracle-${oracleId}`;
164
+ console.log('checking admin for oracle key '+oracleKey)
165
+ const oracleDB = await db.getDatabase('oracleList');
166
+ const oracleData = await oracleDB.findOneAsync({ _id: oracleKey });
167
+
168
+ if (oracleData && oracleData.name.adminAddress === senderAddress) {
169
+ return true; // The sender is the admin
170
+ } else {
171
+ return false; // The sender is not the admin
172
+ }
173
+ } catch (error) {
174
+ console.error(`Error verifying admin for oracle ${oracleId}:`, error);
175
+ throw error;
176
+ }
177
+ }
178
+
179
+ static async verifyAdmin(oracleId, adminAddress) {
180
+ const oracleKey = `oracle-${oracleId}`;
181
+
182
+ // Check in-memory map first
183
+ const instance = OracleList.getInstance();
184
+ let oracle = instance.oracles.get(oracleKey);
185
+
186
+ // If not found in-memory, check the database
187
+ if (!oracle) {
188
+ const oracleDB = await db.getDatabase('oracleList');
189
+ oracle = await oracleDB.findOneAsync({ _id: oracleKey });
190
+ }
191
+
192
+ // Verify admin address
193
+ return oracle && oracle.adminAddress === adminAddress;
194
+ }
195
+
196
+
197
+ static async updateAdmin(oracleId, newAdminAddress, backup) {
198
+ const oracleKey = `oracle-${oracleId}`;
199
+ const instance = OracleList.getInstance();
200
+
201
+ // Get the NeDB datastore for oracles
202
+ const oracleDB = await db.getDatabase('oracleList');
203
+
204
+ // Fetch the current oracle data
205
+ const oracle = await oracleDB.findOneAsync({ _id: oracleKey });
206
+
207
+ if (!oracle) {
208
+ throw new Error('Oracle not found');
209
+ }
210
+
211
+ if(backup){
212
+ oracle.backupAddress=newAdminAddress
213
+ }else{
214
+ // Update the admin address
215
+ oracle.adminAddress = newAdminAddress;
216
+ }
217
+
218
+ // Update the oracle in the database
219
+ await oracleDB.updateAsync({ _id: oracleKey }, { $set: { adminAddress: newAdminAddress } }, {});
220
+
221
+ // Optionally, update the in-memory map if you are maintaining one
222
+ this.oracles.set(oracleKey, oracle);
223
+
224
+ console.log(`Oracle ID ${oracleId} admin updated to ${newAdminAddress}`);
225
+ }
226
+
227
+ static async createOracle(name, adminAddress) {
228
+ const instance = OracleList.getInstance(); // Get the singleton instance
229
+ const oracleId = OracleList.getNextId();
230
+ const oracleKey = `oracle-${oracleId}`;
231
+
232
+ const newOracle = {
233
+ _id: oracleKey, // NeDB uses _id as the primary key
234
+ id: oracleId,
235
+ name: name,
236
+ adminAddress: adminAddress,
237
+ data: {} // Initial data, can be empty or preset values
238
+ };
239
+
240
+ // Get the NeDB datastore for oracles
241
+ const oracleDB = await db.getDatabase('oracleList');
242
+
243
+ try {
244
+ // Save the new oracle to the database
245
+ await oracleDB.insertAsync(newOracle);
246
+
247
+ // Also save the new oracle to the in-memory map
248
+ instance.oracles.set(oracleKey, newOracle);
249
+
250
+ console.log(`New oracle created: ID ${oracleId}, Name: ${name}`);
251
+ return oracleId; // Return the new oracle ID
252
+ } catch (error) {
253
+ console.error('Error creating new oracle:', error);
254
+ throw error; // Re-throw the error for the caller to handle
255
+ }
256
+ }
257
+
258
+ static getNextId() {
259
+ const instance = OracleList.getInstance(); // Get the singleton instance
260
+ let maxId = 0;
261
+ for (const key of instance.oracles.keys()) {
262
+ const currentId = parseInt(key.split('-')[1]);
263
+ if (currentId > maxId) {
264
+ maxId = currentId;
265
+ }
266
+ }
267
+ return maxId + 1;
268
+ }
269
+
270
+ async saveOracleData(oracleId, data, blockHeight) {
271
+ const oracleDataDB = await db.getDatabase('oracleData');
272
+ const recordKey = `oracle-${oracleId}-${blockHeight}`;
273
+ console.log('saving published oracle data to key '+recordKey)
274
+ const oracleDataRecord = {
275
+ _id: recordKey,
276
+ oracleId,
277
+ data,
278
+ blockHeight
279
+ };
280
+
281
+ try {
282
+ await oracleDataDB.updateAsync(
283
+ { _id: recordKey },
284
+ oracleDataRecord,
285
+ { upsert: true }
286
+ );
287
+ console.log(`Oracle data record saved successfully: ${recordKey}`);
288
+ } catch (error) {
289
+ console.error(`Error saving oracle data record: ${recordKey}`, error);
290
+ throw error;
291
+ }
292
+ }
293
+
294
+ async loadOracleData(oracleId, startBlockHeight = 0, endBlockHeight = Number.MAX_SAFE_INTEGER) {
295
+ const oracleDataDB = await db.getDatabase('oracleData');
296
+ try {
297
+ const query = {
298
+ oracleId: oracleId,
299
+ blockHeight: { $gte: startBlockHeight, $lte: endBlockHeight }
300
+ };
301
+ const oracleDataRecords = await oracleDataDB.findAsync(query);
302
+ return oracleDataRecords.map(record => ({
303
+ blockHeight: record.blockHeight,
304
+ data: record.data
305
+ }));
306
+ } catch (error) {
307
+ console.error(`Error loading oracle data for oracleId ${oracleId}:`, error);
308
+ throw error;
309
+ }
310
+ }
311
+
312
+ static async closeOracle(oracleId) {
313
+ const instance = OracleList.getInstance();
314
+ const oracleKey = `oracle-${oracleId}`;
315
+ const oracleDB = await db.getDatabase('oracleList');
316
+
317
+ try {
318
+ // Fetch the current oracle data
319
+ const oracle = await oracleDB.findOneAsync({ _id: oracleKey });
320
+
321
+ if (!oracle) {
322
+ throw new Error('Oracle not found');
323
+ }
324
+
325
+ // Mark the oracle as closed
326
+ oracle.closed = true;
327
+
328
+ // Update the oracle in the database
329
+ await oracleDB.updateAsync({ _id: oracleKey }, { $set: { closed: true } }, {});
330
+
331
+ // Update the in-memory map if maintaining one
332
+ instance.oracles.set(oracleKey, oracle);
333
+
334
+ console.log(`Oracle ID ${oracleId} has been closed`);
335
+
336
+ // Call the insurance fund to perform the payout
337
+ await Insurance.liquidate(oracle.adminAddress,true);
338
+
339
+ console.log(`Payout for Oracle ID ${oracleId} completed`);
340
+ } catch (error) {
341
+ console.error(`Error closing oracle ${oracleId}:`, error);
342
+ throw error;
343
+ }
344
+ }
345
+
346
+
347
+ /**
348
+ * Fetches VWAP for an oracle-based contract over `trailingBlocks`
349
+ * @param {number} oracleId - The oracle ID
350
+ * @param {number} blockHeight - The current block height
351
+ * @param {number} trailingBlocks - The number of blocks to look back
352
+ * @returns {Promise<number|null>} - The calculated VWAP or null if no data
353
+ */
354
+ static async getTWAP(oracleId, blockHeight, trailingBlocks) {
355
+ try {
356
+ const oracleDB = await db.getDatabase('oracleData');
357
+ const blockStart = blockHeight - trailingBlocks;
358
+
359
+ // Query oracle data within the block range
360
+ const oracleData = await oracleDB.findAsync({
361
+ oracleId,
362
+ blockHeight: { $gte: blockStart, $lte: blockHeight }
363
+ });
364
+
365
+ if (!oracleData || oracleData.length === 0) {
366
+ //console.warn(`⚠️ No Oracle VWAP data for oracle ${oracleId} in blocks ${blockStart}-${blockHeight}`);
367
+ return null;
368
+ }
369
+
370
+ // Calculate VWAP
371
+ let totalVolume = new BigNumber(0);
372
+ let sumVolumeTimesPrice = new BigNumber(0);
373
+
374
+ for (const entry of oracleData) {
375
+ const price = new BigNumber(entry.data.price);
376
+ const volume = new BigNumber(1); // Assume equal weight for each oracle entry
377
+
378
+ totalVolume = totalVolume.plus(volume);
379
+ sumVolumeTimesPrice = sumVolumeTimesPrice.plus(volume.times(price));
380
+ }
381
+
382
+ if (totalVolume.isZero()) return null;
383
+
384
+ return sumVolumeTimesPrice.dividedBy(totalVolume).decimalPlaces(8).toNumber();
385
+ } catch (error) {
386
+ console.error(`❌ Error fetching VWAP for oracle ${oracleId}:`, error);
387
+ return null;
388
+ }
389
+ }
390
+
391
+ // Additional methods for managing oracles
392
+ }
393
+
394
+ module.exports = OracleList;