Implement everything until the mixing starts
MODIFY
.gitignore
.gitignore
@@ -248,3 +248,7 @@ FullBlockSpvData
/HiddenWallet/HiddenWallet.API/Config.json
TorData
tor
+/HiddenWallet/HiddenWallet.API/TumbleBitData/TestNet/db2/Configuration
+/HiddenWallet/HiddenWallet.GUI/TumbleBitData/TestNet/db2/Configuration
+/HiddenWallet/HiddenWallet.GUI/torchangelog.txt
+/HiddenWallet/HiddenWallet.API/torchangelog.txt

MODIFY
HiddenWallet/HiddenWallet.API/Config.cs
HiddenWallet/HiddenWallet.API/Config.cs
@@ -84,7 +84,7 @@ namespace HiddenWallet.API
if (rawContent.TumbleBitServerMainNet == null || rawContent.TumbleBitServerMainNet == "")
{
- TumbleBitServerTestNet = null;
+ TumbleBitServerMainNet = null;
}
else TumbleBitServerMainNet = new Uri(rawContent.TumbleBitServerMainNet);
}

MODIFY
HiddenWallet/HiddenWallet.API/Controllers/WalletController.cs
HiddenWallet/HiddenWallet.API/Controllers/WalletController.cs
@@ -313,5 +313,19 @@ namespace HiddenWallet.API.Controllers
return new ObjectResult(new FailureResponse { Message = ex.Message, Details = ex.ToString() });
}
}
+
+ [Route("tumbler-server")]
+ [HttpGet]
+ public IActionResult TumblerServer()
+ {
+ try
+ {
+ return new ObjectResult(Global.WalletWrapper.GetTumblerServerResponse());
+ }
+ catch (Exception ex)
+ {
+ return new ObjectResult(new FailureResponse { Message = ex.Message, Details = ex.ToString() });
+ }
+ }
}
}

MODIFY
HiddenWallet/HiddenWallet.API/HiddenWallet.API.csproj
HiddenWallet/HiddenWallet.API/HiddenWallet.API.csproj
<RuntimeIdentifiers>win7-x64;win8-x64;win81-x64;win10-x64;osx.10.10-x64;osx.10.11-x64;osx.10.12-x64;ubuntu.14.04-x64;ubuntu.14.10-x64;ubuntu.15.04-x64;ubuntu.15.10-x64;ubuntu.16.04-x64;ubuntu.16.10-x64;debian.8-x64;linuxmint.17-x64;linuxmint.17.1-x64;linuxmint.17.2-x64;linuxmint.17.3-x64;linuxmint.18-x64;win7-x86;win8-x86;win81-x86;win10-x86</RuntimeIdentifiers>
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="HBitcoin" Version="0.2.0" />
+ <PackageReference Include="HBitcoin" Version="0.2.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Routing" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.2" />

MODIFY
HiddenWallet/HiddenWallet.API/Wrappers/WalletWrapper.cs
HiddenWallet/HiddenWallet.API/Wrappers/WalletWrapper.cs
@@ -15,6 +15,7 @@ using System.Threading;
using System.Threading.Tasks;
using static HBitcoin.FullBlockSpv.WalletJob;
using DotNetTor.SocksPort;
+using HBitcoin.TumbleBit.ClassicTumbler;
namespace HiddenWallet.API.Wrappers
{
@@ -285,5 +286,38 @@ namespace HiddenWallet.API.Wrappers
if (result.Success) return new SuccessResponse();
else return new FailureResponse { Message = result.FailingReason, Details = "" };
}
+
+ public TumblerServerResponse GetTumblerServerResponse()
+ {
+ var addressUri = Network == Network.Main ? Config.TumbleBitServerMainNet : Config.TumbleBitServerTestNet;
+ var address = "";
+ if (addressUri != null)
+ {
+ address = addressUri.AbsoluteUri;
+ }
+
+ if(address == "" || _walletJob.UseTumbleBit == false)
+ {
+ return new TumblerServerResponse { Address = address, Status = "TumbleBitConfiguredToBeNotUsed", Denomination = "", FeePercent = "", SatoshiFeePerBytes = "", CycleLengthMinutes = "" };
+ }
+
+ if (_walletJob.TumbleBitSetupSuccessful == false)
+ {
+ return new TumblerServerResponse { Address = address, Status = "TumblerServerIssues", Denomination = "", FeePercent = "", SatoshiFeePerBytes = "", CycleLengthMinutes = "" };
+ }
+ var satoshiFeePerBytes = _walletJob.TumbleBitRuntime.Services.FeeService.GetFeeRate().FeePerK.ToDecimal(MoneyUnit.Satoshi) / 1000;
+ var periods = _walletJob.TumbleBitRuntime.TumblerParameters.CycleGenerator.FirstCycle.GetPeriods();
+ var lengthBlocks = periods.Total.End - periods.Total.Start;
+ var cycleLengthMinutes = lengthBlocks * 10;
+
+ var denomination = _walletJob.TumbleBitRuntime.TumblerParameters.Denomination.ToDecimal(MoneyUnit.BTC);
+ var fee = _walletJob.TumbleBitRuntime.TumblerParameters.Fee.ToDecimal(MoneyUnit.BTC);
+ var feePercent = (fee / denomination) * 100;
+ var fps = feePercent.ToString("0.##");
+ var ds = denomination.ToString(CultureInfo.InvariantCulture);
+ var sfpb = satoshiFeePerBytes.ToString(CultureInfo.InvariantCulture);
+ var slm = cycleLengthMinutes.ToString(CultureInfo.InvariantCulture);
+ return new TumblerServerResponse { Address = address, Status = "Online", Denomination = ds, FeePercent = fps, SatoshiFeePerBytes = sfpb, CycleLengthMinutes = slm };
+ }
}
}

MODIFY
HiddenWallet/HiddenWallet.GUI/app/html/wallet-content.html
HiddenWallet/HiddenWallet.GUI/app/html/wallet-content.html
<div id="receive-content">
<label>Unused Receive Addresses:</label>
- <ul id="receive-addresses" class="list-group">
- </ul>
+ <ul id="receive-addresses" class="list-group"></ul>
<label>[Advanced] Extended Public Key:</label>
<ul class="list-group">
<li id="extpubkey" class="list-group-item" style="word-wrap:break-word"></li>
<th>Transaction ID</th>
</tr>
</thead>
- <tbody id="history-records">
- </tbody>
+ <tbody id="history-records"></tbody>
</table>
</div>
<input id="tumbler-address" type="text" class="form-control" readonly />
<br />
<label>Status:</label>
- <span class="label" style="font-size: 13px; margin-left:4em;" id="tumbler-status"></span>
+ <span class="label" style="font-size: 13px; margin-left:11.4em;" id="tumbler-status"></span>
<br />
+ <div id="mixer-settings-content">
<label>Denomination:</label>
- <span class="label" style="font-size: 13px;" id="tumbler-denomination"></span>
- <label>BTC</label>
+ <span class="label label-success" style="font-size: 13px; margin-left:7.4em;" id="tumbler-denomination"></span>
<br />
<label>Tumbler Fee:</label>
- <span class="label" style="font-size: 13px; margin-left:0.9em;" id="tumbler-fee"></span>
- <label>%</label>
+ <span class="label label-success" style="font-size: 13px; margin-left:8.4em;" id="tumbler-fee"></span>
+ <br />
+ <label>Time to tumble the first coin:</label>
+ <span style="font-size: 13px;" class="label label-success" id="tumbling-time"></span>
<hr />
<label>From:</label>
- <span class="dropdown">
+ <div class="dropdown">
<span id="choose-wallet-dropdown-active" onclick="chooseWalletDropdown()" style="font-size: 15px; margin-left:2.2em;" class="label label-danger dropbtn"><span class="mdi mdi-arrow-down-drop-circle"></span> Select Wallet!</span>
<div id="choose-wallet-dropdown" class="dropdown-content">
<a id="wallet-dropdown-alice" onclick="chooseWalletDropdown('alice')" href="#">Alice</a>
<a id="wallet-dropdown-bob" onclick="chooseWalletDropdown('bob')" href="#">Bob</a>
</div>
- </span>
+ </div>
<label>To:</label>
<span class="label label-danger" id="tumbling-to-wallet" style="font-size: 15px;">?</span>
<br />
+ <br />
+ <div id="not-enough-funds-to-mix" style="font-size: 13px;" class="alert alert-danger">Not enough funds to mix</div>
+ <div id="wallet-selected">
<form class="form-inline">
<label>Amount:</label>
- <input style="margin-left:1em;" id="amount-input" class="form-control form-inline" onkeypress="document.getElementById('amount-input').stepUp(1); return false;" type="number" size="11" step="0.5" min="0.5" max="5" />
+ <input style="margin-left:1em;" id="amount-input" class="form-control form-inline" onchange="amountChanged()" onkeypress="document.getElementById('amount-input').stepUp(1); return false;" type="number" size="11" />
<label>BTC</label>
</form>
<hr />
- <label>Estimated Tumbling Time:</label>
- <span style="font-size: 13px;" class="label" id="tumbling-time"></span>
- <label>h</label>
- <br />
<label>Estimated Network Fees:</label>
- <span style="font-size: 13px; margin-left:0.6em;" class="label" id="tumbling-network-fees"></span>
- <label>%</label>
+ <span style="font-size: 13px;" class="label label-success" id="tumbling-network-fees"></span>
<br />
<br />
<button id="broadcast-button" class="btn btn-lg btn-success btn-block" onclick="">
<span class="mdi mdi-tor"></span> Start Mixing
</button>
+ </div>
+ </div>
<hr />
<table class="table table-striped">
<thead>

MODIFY
HiddenWallet/HiddenWallet.GUI/app/js/decryption-phase.js
HiddenWallet/HiddenWallet.GUI/app/js/decryption-phase.js
@@ -138,7 +138,7 @@ function decryptWallet() {
obj.password = password;
document.getElementsByClassName("container").item(0).setAttribute("style", "pointer-events:none;");
- document.getElementById("decrypt-wallet-button").innerHTML = '<span class="glyphicon glyphicon-cog spinning"></span> Decrypting...';
+ document.getElementById("decrypt-wallet-button").innerHTML = '<span class="glyphicon glyphicon-cog spinning"></span> Initializing...';
httpPostWalletAsync("load", obj, function (json) {
if (json.Success == false) {
alert("Could not decrypt wallet, details:\n\n" + json.Message);

MODIFY
HiddenWallet/HiddenWallet.GUI/app/js/status.js
HiddenWallet/HiddenWallet.GUI/app/js/status.js
@@ -7,16 +7,17 @@ function statusShow(progress, text, progressType = "") {
}
}
-var changeBump = 0;
-var walletState;
-var headerHeight;
-var trackingHeight;
-var connectedNodeCount;
-var memPoolTransactionCount;
-var torState;
+let blocksLeftToSync;
+let changeBump = 0;
+let walletState;
+let headerHeight;
+let trackingHeight;
+let connectedNodeCount;
+let memPoolTransactionCount;
+let torState;
function periodicUpdate() {
setInterval(function statusUpdate() {
- var response = httpGetWallet("status");
+ let response = httpGetWallet("status");
if (walletState === response.WalletState) {
if (headerHeight === response.HeaderHeight) {
@@ -41,17 +42,18 @@ function periodicUpdate() {
memPoolTransactionCount = response.MemPoolTransactionCount;
torState = response.TorState;
- var connectionText = "Connecting..."
+ let connectionText = "Connecting..."
if (connectedNodeCount !== 0) {
connectionText = "Connections: " + connectedNodeCount;
}
- var blocksLeft = "-";
+ let blocksLeft = "-";
if (trackingHeight !== 0) {
blocksLeft = headerHeight - trackingHeight;
}
+ blocksLeftToSync = blocksLeft;
- var text = "";
- var progressType = "";
+ let text = "";
+ let progressType = "";
if (walletState.toUpperCase() === "NotStarted".toUpperCase()) {
progressType = "info";
text = "Tor circuit estabilished, Wallet is offline";

MODIFY
HiddenWallet/HiddenWallet.GUI/app/js/wallet-phase.js
HiddenWallet/HiddenWallet.GUI/app/js/wallet-phase.js
@@ -67,41 +67,87 @@ function walletShow(menuItem) {
/* When the user clicks on the button,
toggle between hiding and showing the dropdown content */
function chooseWalletDropdown(aliceBob = "") {
+ let balances;
if (aliceBob === "") {
document.getElementById("choose-wallet-dropdown").classList.toggle("show");
}
else if (aliceBob === "alice") {
document.getElementById("choose-wallet-dropdown-active").innerHTML = "Alice";
- document.getElementById("choose-wallet-dropdown-active").classList.remove("label-danger");
- document.getElementById("choose-wallet-dropdown-active").classList.add("label-success");
document.getElementById("tumbling-to-wallet").innerHTML = "Bob";
- document.getElementById("tumbling-to-wallet").classList.remove("label-danger");
- document.getElementById("tumbling-to-wallet").classList.add("label-success");
+ resp = httpGetWallet("balances/alice");
}
else if (aliceBob === "bob") {
document.getElementById("choose-wallet-dropdown-active").innerHTML = "Bob";
+ document.getElementById("tumbling-to-wallet").innerHTML = "Alice";
+ resp = httpGetWallet("balances/bob");
+ }
+ if (aliceBob === "bob" || aliceBob === "alice") {
document.getElementById("choose-wallet-dropdown-active").classList.remove("label-danger");
document.getElementById("choose-wallet-dropdown-active").classList.add("label-success");
- document.getElementById("tumbling-to-wallet").innerHTML = "Alice";
document.getElementById("tumbling-to-wallet").classList.remove("label-danger");
document.getElementById("tumbling-to-wallet").classList.add("label-success");
+
+ let maximumMixed = resp.Available - (resp.Available * (tumblerFeePercent / 100));
+
+ if (maximumMixed < tumblerDenomination) {
+ document.getElementById("not-enough-funds-to-mix").style.removeProperty("display");
+ document.getElementById("wallet-selected").style.display = "none";
+ }
+ else {
+ var times = Math.floor(maximumMixed / tumblerDenomination);
+ maximumMixed -= (estCycleFee * times);
+ document.getElementById("wallet-selected").style.removeProperty("display");
+ document.getElementById("not-enough-funds-to-mix").style.display = "none";
+ document.getElementById("amount-input").step = tumblerDenomination;
+ document.getElementById("amount-input").min = tumblerDenomination;
+ document.getElementById("amount-input").max = maximumMixed;
+ document.getElementById("amount-input").value = tumblerDenomination;
+ document.getElementById("tumbling-network-fees").innerText = estCycleFee + " BTC";
}
}
+}
+
+function amountChanged() {
+ let cycleCount = document.getElementById("amount-input").value / tumblerDenomination;
+ document.getElementById("tumbling-network-fees").innerText = cycleCount * estCycleFee + " BTC";
+}
+let tumblerAddress;
+let tumblerDenomination;
+let tumblerFeePercent;
+let tumblerFeeRate;
+let estCycleFee;
function mixerShow() {
document.getElementById("content").innerHTML = document.getElementById("wallet-content-frame").contentWindow.document.getElementById("mixer-content").outerHTML;
+ let resp = httpGetWallet("tumbler-server");
+ tumblerAddress = resp.Address;
+ tumblerDenomination = resp.Denomination;
+ tumblerFeePercent = resp.FeePercent;
+ tumblerFeeRate = resp.SatoshiFeePerBytes;
+ estCycleFee = tumblerFeeRate * (380 + 310) * 2 * 0.00000001;
- document.getElementById("tumbler-address").value = "http://testnet.ntumblebit.metaco.com/api/v1/tumblers/7c762c3dc672d440a9a0ed3082a2fc5fbfcc51db";
- document.getElementById("tumbler-status").innerText = "Online";
+ document.getElementById("tumbler-address").value = resp.Address;
+
+ document.getElementById("tumbler-status").innerText = resp.Status;
+ if (blocksLeftToSync !== 0 && blocksLeftToSync !== 1 && blocksLeftToSync !== 2) {
+ document.getElementById("tumbler-status").innerText = "WalletIsNotSynced";
+ document.getElementById("tumbler-status").classList.add("label-danger");
+ document.getElementById("mixer-settings-content").style.display = "none";
+ }
+ else if (resp.Status.toUpperCase() != "online".toUpperCase()) {
+ document.getElementById("tumbler-status").classList.add("label-danger");
+ document.getElementById("mixer-settings-content").style.display = "none";
+ }
+ else {
document.getElementById("tumbler-status").classList.add("label-success");
- document.getElementById("tumbler-denomination").innerText = "0.7";
- document.getElementById("tumbler-denomination").classList.add("label-warning");
- document.getElementById("tumbler-fee").innerText = "1.01";
- document.getElementById("tumbler-fee").classList.add("label-warning");
- document.getElementById("tumbling-time").innerText = "3";
- document.getElementById("tumbling-time").classList.add("label-warning");
- document.getElementById("tumbling-network-fees").innerText = "2.2";
- document.getElementById("tumbling-network-fees").classList.add("label-warning");
+
+ document.getElementById("tumbler-denomination").innerText = resp.Denomination + " BTC";
+ document.getElementById("tumbler-fee").innerText = resp.FeePercent + " %";
+ document.getElementById("tumbling-time").innerText = Math.round((resp.CycleLengthMinutes / 60) * 10) / 10 + " hours";
+
+ document.getElementById("wallet-selected").style.display = "none";
+ document.getElementById("not-enough-funds-to-mix").style.display = "none";
+ }
}
function updateWalletContent() {

Implement everything until the mixing starts