github.com/cryptohub-digital/blockbook-fork@v0.0.0-20230713133354-673c927af7f1/static/test-websocket.html (about)

     1  <!doctype html>
     2  <html lang="en">
     3  
     4  <head>
     5      <meta charset="utf-8">
     6      <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
     7      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
     8      <style>
     9          .row {
    10              margin-top: 1%;
    11          }
    12  
    13          ::placeholder {
    14              color: #ccc !important;
    15          }
    16      </style>
    17      <title>Blockbook Websocket Test Page</title>
    18      <script>
    19          var ws;
    20          var messageID;
    21          var pendingMessages;
    22          var subscriptions;
    23          function send(method, params, callback) {
    24              var id = messageID.toString();
    25              messageID++;
    26              pendingMessages[id] = callback;
    27              var req = {
    28                  id,
    29                  method,
    30                  params
    31              }
    32              ws.send(JSON.stringify(req));
    33              return id;
    34          }
    35          function subscribe(method, params, callback) {
    36              var id = messageID.toString();
    37              messageID++;
    38              subscriptions[id] = callback;
    39              var req = {
    40                  id,
    41                  method,
    42                  params
    43              }
    44              ws.send(JSON.stringify(req));
    45              return id;
    46          }
    47          function unsubscribe(method, id, params, callback) {
    48              delete subscriptions[id];
    49              pendingMessages[id] = callback;
    50              var req = {
    51                  id,
    52                  method,
    53                  params
    54              }
    55              ws.send(JSON.stringify(req));
    56              return id;
    57          }
    58          function connect(server) {
    59              messageID = 0;
    60              pendingMessages = {};
    61              subscriptions = {};
    62              subscribeNewBlockId = "";
    63              subscribeNewTransactionId = "";
    64              subscribeAddressesId = "";
    65              if (server.startsWith("http")) {
    66                  server = server.replace("http", "ws");
    67              }
    68              if (!server.endsWith("/websocket")) {
    69                  server += "/websocket";
    70              }
    71              ws = new WebSocket(server);
    72              ws.onopen = function (e) {
    73                  console.log('socket connected', e);
    74                  document.getElementById('connectionStatus').innerText = "connected";
    75              };
    76              ws.onclose = function (e) {
    77                  console.log('socket closed', e);
    78                  document.getElementById('connectionStatus').innerText = "disconnected";
    79              };
    80              ws.onerror = function (e) {
    81                  console.log('socket error ', e);
    82                  document.getElementById('connectionStatus').innerText = "error";
    83              };
    84              ws.onmessage = function (e) {
    85                  console.log('resp ' + e.data);
    86                  var resp = JSON.parse(e.data);
    87                  var f = pendingMessages[resp.id];
    88                  if (f != undefined) {
    89                      delete pendingMessages[resp.id];
    90                      f(resp.data);
    91                  } else {
    92                      f = subscriptions[resp.id];
    93                      if (f != undefined) {
    94                          f(resp.data);
    95                      }
    96                      else {
    97                          console.log("unkown response " + resp.id);
    98                      }
    99                  }
   100              };
   101          }
   102          function paramAsArray(name) {
   103              const p = document.getElementById(name).value;
   104              if (p) {
   105                  return p.split(",").map(s => s.trim());
   106              }
   107          }
   108  
   109          function getInfo() {
   110              const method = 'getInfo';
   111              const params = {
   112              };
   113              send(method, params, function (result) {
   114                  document.getElementById('getInfoResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   115              });
   116          }
   117  
   118          function ping() {
   119              const method = 'ping';
   120              const params = {
   121              };
   122              send(method, params, function (result) {
   123                  document.getElementById('pingResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   124              });
   125          }
   126  
   127          function getBlockHash() {
   128              const method = 'getBlockHash';
   129              const height = parseInt(document.getElementById("getBlockHashHeight").value);
   130              const params = {
   131                  height
   132              };
   133              send(method, params, function (result) {
   134                  document.getElementById('getBlockHashResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   135              });
   136          }
   137  
   138          function getBlock() {
   139              const method = "getBlock";
   140              const id = document.getElementById("getBlockId").value;
   141              const page = parseInt(document.getElementById("getBlockPage").value);
   142              const pageSize = parseInt(document.getElementById("getBlockPageSize").value);
   143              const params = {
   144                  id,
   145              };
   146              if (page) params.page = page;
   147              if (pageSize) params.pageSize = pageSize;
   148              send(method, params, function (result) {
   149                  document.getElementById("getBlockResult").innerText = JSON.stringify(result).replace(/,/g, ", ");
   150              });
   151          }
   152  
   153          function getAccountInfo() {
   154              const descriptor = document.getElementById('getAccountInfoDescriptor').value.trim();
   155              const selectDetails = document.getElementById('getAccountInfoDetails');
   156              const details = selectDetails.options[selectDetails.selectedIndex].value;
   157              const page = parseInt(document.getElementById("getAccountInfoPage").value);
   158              const from = parseInt(document.getElementById("getAccountInfoFrom").value);
   159              const to = parseInt(document.getElementById("getAccountInfoTo").value);
   160              const contractFilter = document.getElementById("getAccountInfoContract").value.trim();
   161              const secondaryCurrency = document.getElementById("getAccountInfoSecondaryCurrency").value.trim();
   162              const pageSize = 10;
   163              const method = 'getAccountInfo';
   164              const tokens = "derived"; // could be "nonzero", "used", default is "derived" i.e. all
   165              const params = {
   166                  descriptor,
   167                  details,
   168                  tokens,
   169                  page,
   170                  pageSize,
   171                  from,
   172                  to,
   173                  contractFilter,
   174                  secondaryCurrency,
   175                  // default gap=20
   176              };
   177              send(method, params, function (result) {
   178                  document.getElementById('getAccountInfoResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   179              });
   180          }
   181  
   182          function getAccountUtxo() {
   183              const descriptor = document.getElementById('getAccountUtxoDescriptor').value.trim();
   184              const method = 'getAccountUtxo';
   185              const params = {
   186                  descriptor,
   187              };
   188              send(method, params, function (result) {
   189                  document.getElementById('getAccountUtxoResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   190              });
   191          }
   192  
   193          function getBalanceHistory() {
   194              const descriptor = document.getElementById('getBalanceHistoryDescriptor').value.trim();
   195              const from = parseInt(document.getElementById("getBalanceHistoryFrom").value.trim());
   196              const to = parseInt(document.getElementById("getBalanceHistoryTo").value.trim());
   197              const currencies = paramAsArray('getBalanceHistoryFiat');
   198              const groupBy = parseInt(document.getElementById("getBalanceHistoryGroupBy").value);
   199              const method = 'getBalanceHistory';
   200              const params = {
   201                  descriptor,
   202                  from,
   203                  to,
   204                  currencies,
   205                  groupBy
   206                  // default gap=20
   207              };
   208              send(method, params, function (result) {
   209                  document.getElementById('getBalanceHistoryResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   210              });
   211          }
   212  
   213  
   214          function getTransaction() {
   215              const txid = document.getElementById('getTransactionTxid').value.trim();
   216              const method = 'getTransaction';
   217              const params = {
   218                  txid,
   219              };
   220              send(method, params, function (result) {
   221                  document.getElementById('getTransactionResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   222              });
   223          }
   224  
   225          function getTransactionSpecific() {
   226              const txid = document.getElementById('getTransactionSpecificTxid').value.trim();
   227              const method = 'getTransactionSpecific';
   228              const params = {
   229                  txid,
   230              };
   231              send(method, params, function (result) {
   232                  document.getElementById('getTransactionSpecificResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   233              });
   234          }
   235  
   236          function estimateFee() {
   237              try {
   238                  var blocks = paramAsArray('estimateFeeBlocks');
   239                  var specific = document.getElementById('estimateFeeSpecific').value.trim();
   240                  if (specific) {
   241                      // example for bitcoin type: {"conservative": false,"txsize":1234}
   242                      // example for ethereum type: {"from":"0x65513ecd11fd3a5b1fefdcc6a500b025008405a2","to":"0x65513ecd11fd3a5b1fefdcc6a500b025008405a2","data":"0xabcd","gasPrice":"0x30d40","value":"0x1234"}
   243                      specific = JSON.parse(specific)
   244                  }
   245                  else {
   246                      specific = undefined;
   247                  }
   248                  blocks = blocks.map(s => parseInt(s.trim()));
   249                  const method = 'estimateFee';
   250                  const params = {
   251                      blocks,
   252                      specific
   253                  };
   254                  send(method, params, function (result) {
   255                      document.getElementById('estimateFeeResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   256                  });
   257              }
   258              catch (e) {
   259                  document.getElementById('estimateFeeResult').innerText = e;
   260              }
   261          }
   262  
   263          function sendTransaction() {
   264              var hex = document.getElementById('sendTransactionHex').value.trim();
   265              const method = 'sendTransaction';
   266              const params = {
   267                  hex,
   268              };
   269              send(method, params, function (result) {
   270                  document.getElementById('sendTransactionResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   271              });
   272          }
   273  
   274          function subscribeNewBlock() {
   275              const method = 'subscribeNewBlock';
   276              const params = {
   277              };
   278              if (subscribeNewBlockId) {
   279                  delete subscriptions[subscribeNewBlockId];
   280                  subscribeNewBlockId = "";
   281              }
   282              subscribeNewBlockId = subscribe(method, params, function (result) {
   283                  document.getElementById('subscribeNewBlockResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n";
   284              });
   285              document.getElementById('subscribeNewBlockId').innerText = subscribeNewBlockId;
   286              document.getElementById('unsubscribeNewBlockButton').setAttribute("style", "display: inherit;");
   287          }
   288  
   289          function unsubscribeNewBlock() {
   290              const method = 'unsubscribeNewBlock';
   291              const params = {
   292              };
   293              unsubscribe(method, subscribeNewBlockId, params, function (result) {
   294                  subscribeNewBlockId = "";
   295                  document.getElementById('subscribeNewBlockResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n";
   296                  document.getElementById('subscribeNewBlockId').innerText = "";
   297                  document.getElementById('unsubscribeNewBlockButton').setAttribute("style", "display: none;");
   298              });
   299          }
   300  
   301          function subscribeNewTransaction() {
   302              const method = 'subscribeNewTransaction';
   303              const params = {
   304              };
   305              if (subscribeNewTransactionId) {
   306                  delete subscriptions[subscribeNewTransactionId];
   307                  subscribeNewTransactionId = "";
   308              }
   309              subscribeNewTransactionId = subscribe(method, params, function (result) {
   310                  document.getElementById('subscribeNewTransactionResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n";
   311              });
   312              document.getElementById('subscribeNewTransactionId').innerText = subscribeNewTransactionId;
   313              document.getElementById('unsubscribeNewTransactionButton').setAttribute("style", "display: inherit;");
   314          }
   315  
   316          function unsubscribeNewTransaction() {
   317              const method = 'unsubscribeNewTransaction';
   318              const params = {
   319              };
   320              unsubscribe(method, subscribeNewTransactionId, params, function (result) {
   321                  subscribeNewTransactionId = "";
   322                  document.getElementById('subscribeNewTransactionResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n";
   323                  document.getElementById('subscribeNewTransactionId').innerText = "";
   324                  document.getElementById('unsubscribeNewTransactionButton').setAttribute("style", "display: none;");
   325              });
   326          }
   327  
   328          function subscribeAddresses() {
   329              const method = 'subscribeAddresses';
   330              var addresses = paramAsArray('subscribeAddressesName');
   331              const params = {
   332                  addresses
   333              };
   334              if (subscribeAddressesId) {
   335                  delete subscriptions[subscribeAddressesId];
   336                  subscribeAddressesId = "";
   337              }
   338              subscribeAddressesId = subscribe(method, params, function (result) {
   339                  document.getElementById('subscribeAddressesResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n";
   340              });
   341              document.getElementById('subscribeAddressesIds').innerText = subscribeAddressesId;
   342              document.getElementById('unsubscribeAddressesButton').setAttribute("style", "display: inherit;");
   343          }
   344  
   345          function unsubscribeAddresses() {
   346              const method = 'unsubscribeAddresses';
   347              const params = {
   348              };
   349              unsubscribe(method, subscribeAddressesId, params, function (result) {
   350                  subscribeAddressesId = "";
   351                  document.getElementById('subscribeAddressesResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n";
   352                  document.getElementById('subscribeAddressesIds').innerText = "";
   353                  document.getElementById('unsubscribeAddressesButton').setAttribute("style", "display: none;");
   354              });
   355          }
   356  
   357          function getFiatRatesForTimestamps() {
   358              const method = 'getFiatRatesForTimestamps';
   359              var timestamps = paramAsArray('getFiatRatesForTimestampsList');
   360              var currencies = paramAsArray('getFiatRatesForTimestampsCurrency');
   361              var token = document.getElementById('getFiatRatesForTimestampsToken').value;
   362              timestamps = timestamps.map(Number);
   363              const params = {
   364                  timestamps,
   365                  'currencies': currencies,
   366                  token,
   367              };
   368              send(method, params, function (result) {
   369                  document.getElementById('getFiatRatesForTimestampsResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   370              });
   371          }
   372  
   373          function getCurrentFiatRates() {
   374              const method = 'getCurrentFiatRates';
   375              var currencies = paramAsArray('getCurrentFiatRatesCurrency');
   376              var token = document.getElementById('getCurrentFiatRatesToken').value;
   377              const params = {
   378                  "currencies": currencies,
   379                  token,
   380              };
   381              send(method, params, function (result) {
   382                  document.getElementById('getCurrentFiatRatesResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   383              });
   384          }
   385  
   386          function getFiatRatesTickersList() {
   387              const method = 'getFiatRatesTickersList';
   388              var timestamp = document.getElementById('getFiatRatesTickersListDate').value;
   389              var token = document.getElementById('getFiatRatesTickersToken').value;
   390              timestamp = parseInt(timestamp);
   391              const params = {
   392                  timestamp,
   393                  token,
   394              };
   395              send(method, params, function (result) {
   396                  document.getElementById('getFiatRatesTickersListResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   397              });
   398          }
   399  
   400          function getMempoolFilters() {
   401              const method = 'getMempoolFilters';
   402              var timestamp = document.getElementById('getMempoolFiltersFromTimestamp').value;
   403              var scriptType = document.getElementById('getMempoolFiltersScriptType').value;
   404              fromTimestamp = parseInt(timestamp);
   405              const params = {
   406                  scriptType,
   407                  fromTimestamp,
   408              };
   409              send(method, params, function (result) {
   410                  document.getElementById('getMempoolFiltersResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
   411              });
   412          }
   413  
   414          function subscribeNewFiatRatesTicker() {
   415              const method = 'subscribeFiatRates';
   416              var currency = document.getElementById('subscribeFiatRatesCurrency').value;
   417              var tokens = paramAsArray('subscribeFiatRatesTokens');
   418              const params = {
   419                  "currency": currency,
   420                  tokens,
   421              };
   422              if (subscribeNewFiatRatesTickerId) {
   423                  delete subscriptions[subscribeNewFiatRatesTickerId];
   424                  subscribeNewFiatRatesTickerId = "";
   425              }
   426              subscribeNewFiatRatesTickerId = subscribe(method, params, function (result) {
   427                  document.getElementById('subscribeNewFiatRatesTickerResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n";
   428              });
   429              document.getElementById('subscribeNewFiatRatesTickerId').innerText = subscribeNewFiatRatesTickerId;
   430              document.getElementById('unsubscribeNewFiatRatesTickerButton').setAttribute("style", "display: inherit;");
   431          }
   432  
   433          function unsubscribeNewFiatRatesTicker() {
   434              const method = 'unsubscribeFiatRates';
   435              const params = {
   436              };
   437              unsubscribe(method, subscribeNewFiatRatesTickerId, params, function (result) {
   438                  subscribeNewFiatRatesTickerId = "";
   439                  document.getElementById('subscribeNewFiatRatesTickerResult').innerText += JSON.stringify(result).replace(/,/g, ", ") + "\n";
   440                  document.getElementById('subscribeNewFiatRatesTickerId').innerText = "";
   441                  document.getElementById('unsubscribeNewFiatRatesTickerButton').setAttribute("style", "display: none;");
   442              });
   443          }
   444      </script>
   445  </head>
   446  
   447  <body>
   448      <div class="container">
   449          <div class="row justify-content-center">
   450              <h1>Blockbook Websocket Test Page</h1>
   451          </div>
   452          <div class="row">
   453              <div class="col">
   454                  <input class="btn btn-secondary" type="button" value="Login" onclick="connect(document.getElementById('serverAddress').value)">
   455              </div>
   456              <div class="col-8">
   457                  <input type="text" class="form-control" id="serverAddress" value="">
   458              </div>
   459              <div class="col form-inline">
   460                  <label id="connectionStatus">not connected</label>
   461              </div>
   462          </div>
   463          <div class="row">
   464              <div class="col">
   465                  <input class="btn btn-secondary" type="button" value="getInfo" onclick="getInfo()">
   466              </div>
   467              <div class="col-10" id="getInfoResult">
   468              </div>
   469          </div>
   470          <div class="row">
   471              <div class="col">
   472                  <input class="btn btn-secondary" type="button" value="ping" onclick="ping()">
   473              </div>
   474              <div class="col-10" id="pingResult">
   475              </div>
   476          </div>
   477          <div class="row">
   478              <div class="col">
   479                  <input class="btn btn-secondary" type="button" value="getBlockHash" onclick="getBlockHash()">
   480              </div>
   481              <div class="col-8">
   482                  <input type="text" class="form-control" placeholder="height" id="getBlockHashHeight" value="0">
   483              </div>
   484              <div class="col">
   485              </div>
   486          </div>
   487          <div class="row">
   488              <div class="col" id="getBlockHashResult"></div>
   489          </div>
   490          <div class="row">
   491              <div class="col">
   492                  <input class="btn btn-secondary" type="button" value="getBlock" onclick="getBlock()">
   493              </div>
   494              <div class="col-8">
   495                  <div class="row" style="margin: 0;">
   496                      <input type="text" class="form-control" placeholder="height/hash" style="width: 68%; margin-right: 5px;" id="getBlockId" value="">
   497                      <input type="text" class="form-control" placeholder="page" style="width: 15%; margin-right: 5px;" id="getBlockPage" value="">
   498                      <input type="text" class="form-control" placeholder="page size" style="width: 15%;" id="getBlockPageSize" value="">
   499                  </div>
   500              </div>
   501              <div class="col">
   502              </div>
   503          </div>
   504          <div class="row">
   505              <div class="col" id="getBlockResult"></div>
   506          </div>
   507          <div class="row">
   508              <div class="col">
   509                  <input class="btn btn-secondary" type="button" value="getAccountInfo" onclick="getAccountInfo()">
   510              </div>
   511              <div class="col-8">
   512                  <div class="row" style="margin: 0;">
   513                      <input type="text" placeholder="descriptor" style="width: 79%" class="form-control" id="getAccountInfoDescriptor" value="0xba98d6a5ac827632e3457de7512d211e4ff7e8bd">
   514                      <select id="getAccountInfoDetails" style="width: 20%; margin-left: 5px;">
   515                          <option value="basic">Basic</option>
   516                          <option value="tokens">Tokens</option>
   517                          <option value="tokenBalances">TokenBalances</option>
   518                          <option value="txids">Txids</option>
   519                          <option value="txs">Transactions</option>
   520                      </select>
   521                  </div>
   522                  <div class="row" style="margin: 0; margin-top: 5px;">
   523                      <input type="text" placeholder="page" style="width: 10%; margin-right: 5px;" class="form-control" id="getAccountInfoPage">
   524                      <input type="text" placeholder="from" style="width: 13%;margin-left: 5px;margin-right: 5px;" class="form-control" id="getAccountInfoFrom">
   525                      <input type="text" placeholder="to" style="width: 13%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getAccountInfoTo">
   526                      <input type="text" placeholder="contract" style="width: 50%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getAccountInfoContract">
   527                      <input type="text" placeholder="usd" style="width: 8%; margin-left: 5px;" class="form-control" id="getAccountInfoSecondaryCurrency">
   528                  </div>
   529              </div>
   530              <div class="col form-inline"></div>
   531          </div>
   532          <div class="row">
   533              <div class="col" id="getAccountInfoResult">
   534              </div>
   535          </div>
   536          <div class="row">
   537              <div class="col">
   538                  <input class="btn btn-secondary" type="button" value="getAccountUtxo" onclick="getAccountUtxo()">
   539              </div>
   540              <div class="col-8">
   541                  <div class="row" style="margin: 0;">
   542                      <input type="text" placeholder="descriptor" class="form-control" id="getAccountUtxoDescriptor" value="0xba98d6a5ac827632e3457de7512d211e4ff7e8bd">
   543                  </div>
   544              </div>
   545              <div class="col form-inline"></div>
   546          </div>
   547          <div class="row">
   548              <div class="col" id="getAccountUtxoResult">
   549              </div>
   550          </div>
   551          <div class="row">
   552              <div class="col">
   553                  <input class="btn btn-secondary" type="button" value="getBalanceHistory" onclick="getBalanceHistory()">
   554              </div>
   555              <div class="col-8">
   556                  <div class="row" style="margin: 0;">
   557                      <input type="text" placeholder="descriptor" class="form-control" id="getBalanceHistoryDescriptor" value="0xba98d6a5ac827632e3457de7512d211e4ff7e8bd">
   558                  </div>
   559                  <div class="row" style="margin: 0; margin-top: 5px;">
   560                      <input type="text" placeholder="from Unix TS" style="width: 20%;margin-left: 5px;margin-right: 5px;" class="form-control" id="getBalanceHistoryFrom">
   561                      <input type="text" placeholder="to Unix TS" style="width: 20%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getBalanceHistoryTo">
   562                      <input type="text" placeholder="usd,eur" style="width: 20%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getBalanceHistoryFiat">
   563                      <input type="text" placeholder="group by (sec)" style="width: 20%; margin-left: 5px; margin-right: 5px;" class="form-control" id="getBalanceHistoryGroupBy">
   564                  </div>
   565              </div>
   566              <div class="col form-inline"></div>
   567          </div>
   568          <div class="row">
   569              <div class="col" id="getBalanceHistoryResult">
   570              </div>
   571          </div>
   572          <div class="row">
   573              <div class="col">
   574                  <input class="btn btn-secondary" type="button" value="getTransaction" onclick="getTransaction()">
   575              </div>
   576              <div class="col-8">
   577                  <div class="row" style="margin: 0;">
   578                      <input type="text" placeholder="txid" class="form-control" id="getTransactionTxid" value="0xb266c89f9bfefa4aa2fca4e65b7d6c918d5407f464be781c2803f3546d34a574">
   579                  </div>
   580              </div>
   581              <div class="col form-inline"></div>
   582          </div>
   583          <div class="row">
   584              <div class="col" id="getTransactionResult">
   585              </div>
   586          </div>
   587          <div class="row">
   588              <div class="col">
   589                  <input class="btn btn-secondary" type="button" value="getTransactionSpecific" onclick="getTransactionSpecific()">
   590              </div>
   591              <div class="col-8">
   592                  <div class="row" style="margin: 0;">
   593                      <input type="text" placeholder="txid" class="form-control" id="getTransactionSpecificTxid" value="0xb266c89f9bfefa4aa2fca4e65b7d6c918d5407f464be781c2803f3546d34a574">
   594                  </div>
   595              </div>
   596              <div class="col form-inline"></div>
   597          </div>
   598          <div class="row">
   599              <div class="col" id="getTransactionSpecificResult">
   600              </div>
   601          </div>
   602          <div class="row">
   603              <div class="col">
   604                  <input class="btn btn-secondary" type="button" value="estimateFee" onclick="estimateFee()">
   605              </div>
   606              <div class="col-8">
   607                  <div class="row" style="margin: 0;">
   608                      <input type="text" placeholder="comma separated list of block targets" class="form-control" id="estimateFeeBlocks" value="2,5,10,20">
   609                  </div>
   610                  <div class="row" style="margin: 0; margin-top: 5px;">
   611                      <input type="text" placeholder="tx specific JSON" class="form-control" id="estimateFeeSpecific" value="">
   612                  </div>
   613              </div>
   614              <div class="col"></div>
   615          </div>
   616          <div class="row">
   617              <div class="col" id="estimateFeeResult">
   618              </div>
   619          </div>
   620          <div class="row">
   621              <div class="col">
   622                  <input class="btn btn-secondary" type="button" value="sendTransaction" onclick="sendTransaction()">
   623              </div>
   624              <div class="col-8">
   625                  <input type="text" class="form-control" id="sendTransactionHex" value="010000000001019d64f0c72a0d206001decbffaa722eb1044534c74eee7a5df8318e42a4323ec10000000017160014550da1f5d25a9dae2eafd6902b4194c4c6500af6ffffffff02809698000000000017a914cd668d781ece600efa4b2404dc91fd26b8b8aed8870553d7360000000017a914246655bdbd54c7e477d0ea2375e86e0db2b8f80a8702473044022076aba4ad559616905fa51d4ddd357fc1fdb428d40cb388e042cdd1da4a1b7357022011916f90c712ead9a66d5f058252efd280439ad8956a967e95d437d246710bc9012102a80a5964c5612bb769ef73147b2cf3c149bc0fd4ecb02f8097629c94ab013ffd00000000">
   626              </div>
   627              <div class="col">
   628              </div>
   629          </div>
   630          <div class="row">
   631              <div class="col" id="sendTransactionResult"></div>
   632          </div>
   633          <div class="row">
   634              <div class="col-2">
   635                  <input class="btn btn-secondary" type="button" value="get fiat rates for dates" onclick="getFiatRatesForTimestamps()">
   636              </div>
   637              <div class="col-1">
   638                  <input type="text" class="form-control" id="getFiatRatesForTimestampsCurrency" placeholder="usd,eur">
   639              </div>
   640              <div class="col-7">
   641                  <input type="text" class="form-control" id="getFiatRatesForTimestampsList" value="1575288000,1575550800">
   642              </div>
   643              <div class="col-5 offset-3">
   644                  <input type="text" class="form-control" id="getFiatRatesForTimestampsToken" value="" placeholder="Token address">
   645              </div>
   646          </div>
   647          <div class="row">
   648              <div class="col" id="getFiatRatesForTimestampsResult"></div>
   649          </div>
   650          <div class="row">
   651              <div class="col-2">
   652                  <input class="btn btn-secondary" type="button" value="get current fiat rates" onclick="getCurrentFiatRates()">
   653              </div>
   654              <div class="col-1">
   655                  <input type="text" class="form-control" id="getCurrentFiatRatesCurrency" placeholder="usd">
   656              </div>
   657              <div class="col-5">
   658                  <input type="text" class="form-control" id="getCurrentFiatRatesToken" value="" placeholder="Token address">
   659              </div>
   660          </div>
   661          <div class="row">
   662              <div class="col" id="getCurrentFiatRatesResult"></div>
   663          </div>
   664          <div class="row">
   665              <div class="col-2">
   666                  <input class="btn btn-secondary" type="button" value="get available tickers" onclick="getFiatRatesTickersList()">
   667              </div>
   668              <div class="col-4">
   669                  <input type="text" class="form-control" id="getFiatRatesTickersListDate" value="1576591569" placeholder="Unix timestamp">
   670              </div>
   671              <div class="col-5">
   672                  <input type="text" class="form-control" id="getFiatRatesTickersToken" value="" placeholder="Token address">
   673              </div>
   674          </div>
   675          <div class="row">
   676              <div class="col" id="getFiatRatesTickersListResult"></div>
   677          </div>
   678          <div class="row">
   679              <div class="col-2">
   680                  <input class="btn btn-secondary" type="button" value="get mempool filters" onclick="getMempoolFilters()">
   681              </div>
   682              <div class="col-5">
   683                  <input type="text" class="form-control" id="getMempoolFiltersScriptType" value="taproot" placeholder="filter script">
   684              </div>
   685              <div class="col-4">
   686                  <input type="text" class="form-control" id="getMempoolFiltersFromTimestamp" value="" placeholder="From unix timestamp">
   687              </div>
   688          </div>
   689          <div class="row">
   690              <div class="col" id="getMempoolFiltersResult"></div>
   691          </div>
   692          <div class="row">
   693              <div class="col">
   694                  <input class="btn btn-secondary" type="button" value="subscribe new block" onclick="subscribeNewBlock()">
   695              </div>
   696              <div class="col-4">
   697                  <span id="subscribeNewBlockId"></span>
   698              </div>
   699              <div class="col">
   700                  <input class="btn btn-secondary" id="unsubscribeNewBlockButton" style="display: none;" type="button" value="unsubscribe" onclick="unsubscribeNewBlock()">
   701              </div>
   702          </div>
   703          <div class="row">
   704              <div class="col" id="subscribeNewBlockResult"></div>
   705          </div>
   706          <div class="row">
   707              <div class="col">
   708                  <input class="btn btn-secondary" type="button" value="subscribe new transaction" onclick="subscribeNewTransaction()">
   709              </div>
   710              <div class="col-4">
   711                  <span id="subscribeNewTransactionId"></span>
   712              </div>
   713              <div class="col">
   714                  <input class="btn btn-secondary" id="unsubscribeNewTransactionButton" style="display: none;" type="button" value="unsubscribe" onclick="unsubscribeNewTransaction()">
   715              </div>
   716          </div>
   717          <div class="row">
   718              <div class="col" id="subscribeNewTransactionResult"></div>
   719          </div>
   720          <div class="row">
   721              <div class="col">
   722                  <input class="btn btn-secondary" type="button" value="subscribe address" onclick="subscribeAddresses()">
   723              </div>
   724              <div class="col-8">
   725                  <input type="text" class="form-control" id="subscribeAddressesName" value="0xba98d6a5ac827632e3457de7512d211e4ff7e8bd,0x73d0385f4d8e00c5e6504c6030f47bf6212736a8">
   726              </div>
   727              <div class="col">
   728                  <span id="subscribeAddressesIds"></span>
   729              </div>
   730              <div class="col">
   731                  <input class="btn btn-secondary" id="unsubscribeAddressesButton" style="display: none;" type="button" value="unsubscribe" onclick="unsubscribeAddresses()">
   732              </div>
   733          </div>
   734          <div class="row">
   735              <div class="col" id="subscribeAddressesResult"></div>
   736          </div>
   737          <div class="row">
   738              <div class="col-2">
   739                  <input class="btn btn-secondary" type="button" value="subscribe fiat rates" onclick="subscribeNewFiatRatesTicker()">
   740              </div>
   741              <div class="col-1">
   742                  <input type="text" class="form-control" id="subscribeFiatRatesCurrency" value="usd">
   743              </div>
   744              <div class="col-8">
   745                  <input type="text" class="form-control" id="subscribeFiatRatesTokens" value="" placeholder="0xdAC17F958D2ee523a2206206994597C13D831ec7,0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2">
   746              </div>
   747              <div class="col-1">
   748                  <span id="subscribeNewFiatRatesTickerId"></span>
   749              </div>
   750              <div class="col-5">
   751                  <input class="btn btn-secondary" id="unsubscribeNewFiatRatesTickerButton" style="display: none;" type="button" value="unsubscribe" onclick="unsubscribeNewFiatRatesTicker()">
   752              </div>
   753          </div>
   754          <div class="row">
   755              <div class="col" id="subscribeNewFiatRatesTickerResult"></div>
   756          </div>
   757      </div>
   758      <br><br>
   759  </body>
   760  <script>
   761      document.getElementById('serverAddress').value = window.location.protocol + "//" + window.location.host;
   762  </script>
   763  
   764  </html>