Skip to content

Commit

Permalink
Create a faucet for the signet (#28)
Browse files Browse the repository at this point in the history
* Create a faucet for the signet

* only show the button if network is signet

* If a user has coins don't let them, get more coins.

* On first time we use the app add settings if they dont exist
  • Loading branch information
dangershony authored Dec 18, 2023
1 parent 4a7b45b commit bf242da
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 18 deletions.
14 changes: 1 addition & 13 deletions src/Angor/Client/Pages/Settings.razor
Original file line number Diff line number Diff line change
Expand Up @@ -131,19 +131,7 @@

protected override Task OnInitializedAsync()
{
settingsInfo = _clientStorage.GetSettingsInfo();

if(!settingsInfo.Indexers.Any())
{
settingsInfo.Indexers.AddRange(_networkConfiguration.GetDefaultIndexerUrls());
_clientStorage.SetSettingsInfo(settingsInfo);
}

if(!settingsInfo.Relays.Any())
{
settingsInfo.Relays.AddRange(_networkConfiguration.GetDefaultRelayUrls());
_clientStorage.SetSettingsInfo(settingsInfo);
}
_networkService.AddSettingsIfNotExist();

networkType = _networkConfiguration.GetNetwork().Name;

Expand Down
37 changes: 36 additions & 1 deletion src/Angor/Client/Pages/Wallet.razor
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
@using Angor.Shared.Models
@using Angor.Client.Components

@inject HttpClient _httpClient;
@inject IClientStorage storage;
@inject IWalletStorage _walletStorage;
@inject ILogger<Wallet> Logger;
Expand Down Expand Up @@ -163,7 +164,12 @@
<div class="col-lg-6">
<h4 class="card-title">Receive Address</h4>
<p id="receive-address" class="card-text">@nextReceiveAddress</p>
<button class="btn btn-primary" onclick="@CopyNextReceiveAddress">Copy Address</button>
<button class="btn btn-primary mr-2" onclick="@CopyNextReceiveAddress">Copy Address</button>

@if (network.NetworkType == NetworkType.Testnet)
{
<button class="btn btn-secondary" @onclick="GetTestCoins">Get some test coins</button>
}
</div>

<ShowQrCode @ref="showQrCode" Data="@nextReceiveAddress" />
Expand Down Expand Up @@ -660,4 +666,33 @@
coinControlModal = true;
StateHasChanged();
}

private async Task GetTestCoins()
{
if (Money.Satoshis(localAccountInfo.TotalBalance).ToUnit(MoneyUnit.BTC) > 10)
{
notificationComponent.ShowNotificationMessage("you already have coins!");
return;
}

var operationResult = await notificationComponent.LongOperation(async () =>
{
var res = await _httpClient.GetAsync($"/api/faucet/send/{localAccountInfo.GetNextReceiveAddress()}");

if (res.IsSuccessStatusCode)
{
var trxhex = await res.Content.ReadAsStringAsync();
var trx = network.CreateTransaction(trxhex);
localAccountInfo.TotalUnConfirmedBalance = trx.Outputs.FirstOrDefault()?.Value.Satoshi ?? 50;
return new OperationResult { Success = true };
}

return new OperationResult { Success = false, Message = await res.Content.ReadAsStringAsync()};
});

if (operationResult is { Success: true })
{
notificationComponent.ShowNotificationMessage("Success!");
}
}
}
2 changes: 2 additions & 0 deletions src/Angor/Client/Shared/NavMenu.razor
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@

protected override async Task OnInitializedAsync()
{
_networkService.AddSettingsIfNotExist();

await _networkService.CheckServices();

await base.OnInitializedAsync();
Expand Down
147 changes: 147 additions & 0 deletions src/Angor/Server/FaucetController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
using Angor.Server;
using Angor.Shared;
using Angor.Shared.Models;
using Angor.Shared.ProtocolNew;
using Blockcore.Consensus.TransactionInfo;
using Blockcore.NBitcoin.BIP39;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using Angor.Client.Services;
using Angor.Shared.Services;
using Blockcore.NBitcoin;
using Blockcore.NBitcoin.BIP32;
using Blockcore.Networks;
using ExtPubKey = Blockcore.NBitcoin.BIP32.ExtPubKey;
using Network = Blockcore.Networks.Network;
using static System.Runtime.InteropServices.JavaScript.JSType;
using TransactionBuilder = Blockcore.Consensus.TransactionInfo.TransactionBuilder;
using BitcoinWitPubKeyAddress = Blockcore.NBitcoin.BitcoinWitPubKeyAddress;
using Money = Blockcore.NBitcoin.Money;
using Transaction = Blockcore.Consensus.TransactionInfo.Transaction;

namespace Blockcore.AtomicSwaps.Server.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class FaucetController : ControllerBase
{
private readonly IWalletOperations _walletOperations;
private readonly IIndexerService _indexerService;
private readonly IHdOperations _hdOperations;
private readonly INetworkConfiguration _networkConfiguration;

private List<UtxoData> PendingUtxo = new ();

public FaucetController(IWalletOperations walletOperations, IIndexerService indexerService, IHdOperations hdOperations, INetworkConfiguration networkConfiguration)
{
_walletOperations = walletOperations;
_indexerService = indexerService;
_hdOperations = hdOperations;
_networkConfiguration = networkConfiguration;
}

[HttpGet]
[Route("send/{address}/{amount?}")]
public async Task<IActionResult> Send(string address, long? amount)
{
var network = _networkConfiguration.GetNetwork();

//var mnemonic = new Mnemonic(wrods);
var words = new WalletWords { Words = "margin radio diamond leg loud street announce guitar video shiver speed eyebrow" };

var accountInfo = _walletOperations.BuildAccountInfoForWalletWords(words);

// the miners address with all the utxos
var addressInfo = GenerateAddressFromPubKey(0, _networkConfiguration.GetNetwork(), false, ExtPubKey.Parse(accountInfo.ExtPubKey, _networkConfiguration.GetNetwork()));

List<UtxoDataWithPath> list = new();

if (!PendingUtxo.Any())
{
// we assume a miner wallet so for now just ignore amounts and send a utxo to the request address
var utxos = await _indexerService.FetchUtxoAsync(addressInfo.Address, 510, 5);

lock (PendingUtxo)
{
if (!PendingUtxo.Any())
{
PendingUtxo.AddRange(utxos);
}
}
}

lock (PendingUtxo)
{
list = new() { new UtxoDataWithPath { HdPath = addressInfo.HdPath, UtxoData = PendingUtxo.First() } };
PendingUtxo.Remove(PendingUtxo.First());
}

var (coins, keys) = _walletOperations.GetUnspentOutputsForTransaction(words, list);

Transaction trx = network.CreateTransaction();
trx.AddOutput(Money.Satoshis(list.First().UtxoData.value) - Money.Satoshis(10000), BitcoinWitPubKeyAddress.Create(address, network));
trx.AddInput(new TxIn { PrevOut = list.First().UtxoData.outpoint.ToOutPoint() });

var signedTransaction = new TransactionBuilder(network)
.AddCoins(coins)
.AddKeys(keys.ToArray())
.SignTransaction(trx);

var res = await _walletOperations.PublishTransactionAsync(network, signedTransaction);

if (res.Success)
{
return Ok(signedTransaction.ToHex(_networkConfiguration.GetNetwork().Consensus.ConsensusFactory));
}

return BadRequest(res.Message);
}

private AddressInfo GenerateAddressFromPubKey(int scanIndex, Network network, bool isChange, ExtPubKey accountExtPubKey)
{
var pubKey = _hdOperations.GeneratePublicKey(accountExtPubKey, scanIndex, isChange);
var path = _hdOperations.CreateHdPath(84, network.Consensus.CoinType, 0, isChange, scanIndex);
var address = pubKey.GetSegwitAddress(network).ToString();

return new AddressInfo { Address = address, HdPath = path };
}
}

public class NetworkServiceMock : INetworkService
{
public Task CheckServices(bool force = false)
{
throw new NotImplementedException();
}

public void AddSettingsIfNotExist()
{
throw new NotImplementedException();
}

public SettingsUrl GetPrimaryIndexer()
{
return new SettingsUrl { Url = "https://tbtc.indexer.angor.io" };
}

public SettingsUrl GetPrimaryRelay()
{
throw new NotImplementedException();
}

public List<SettingsUrl> GetRelays()
{
throw new NotImplementedException();
}

public void CheckAndHandleError(HttpResponseMessage httpResponseMessage)
{

}

public void HandleException(Exception exception)
{
throw exception;
}
}
}
6 changes: 6 additions & 0 deletions src/Angor/Server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
using Angor.Client;
using Angor.Shared;
using Blockcore.AtomicSwaps.Server.Controllers;
using Angor.Client.Services;
using Angor.Shared.Services;

var builder = WebApplication.CreateBuilder(args);

Expand All @@ -20,7 +22,11 @@

// types needed to build investor sigs
builder.Services.AddSingleton<INetworkConfiguration, NetworkConfiguration>();
builder.Services.AddSingleton<INetworkService, NetworkServiceMock>();
builder.Services.AddSingleton<IHdOperations, HdOperations>();
builder.Services.AddSingleton<IWalletOperations, WalletOperations>();
builder.Services.AddSingleton<IIndexerService, IndexerService>();
builder.Services.AddSingleton<HttpClient>();
builder.Services.AddSingleton<IDerivationOperations, DerivationOperations>();
builder.Services.AddSingleton<IFounderTransactionActions, FounderTransactionActions>();
builder.Services.AddSingleton<ISeederTransactionActions, SeederTransactionActions>();
Expand Down
4 changes: 1 addition & 3 deletions src/Angor/Shared/Services/INetworkService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ namespace Angor.Shared.Services;
public interface INetworkService
{
Task CheckServices(bool force = false);

void AddSettingsIfNotExist();
SettingsUrl GetPrimaryIndexer();
SettingsUrl GetPrimaryRelay();
List<SettingsUrl> GetRelays();

void CheckAndHandleError(HttpResponseMessage httpResponseMessage);

void HandleException(Exception exception);
}
21 changes: 20 additions & 1 deletion src/Angor/Shared/Services/NetworkService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,31 @@ public class NetworkService : INetworkService
private readonly INetworkStorage _networkStorage;
private readonly HttpClient _httpClient;
private readonly ILogger<NetworkService> _logger;
private readonly INetworkConfiguration _networkConfiguration;

public NetworkService(INetworkStorage networkStorage, HttpClient httpClient, ILogger<NetworkService> logger)
public NetworkService(INetworkStorage networkStorage, HttpClient httpClient, ILogger<NetworkService> logger, INetworkConfiguration networkConfiguration)
{
_networkStorage = networkStorage;
_httpClient = httpClient;
_logger = logger;
_networkConfiguration = networkConfiguration;
}

public void AddSettingsIfNotExist()
{
var settings = _networkStorage.GetSettings();

if (!settings.Indexers.Any())
{
settings.Indexers.AddRange(_networkConfiguration.GetDefaultIndexerUrls());
_networkStorage.SetSettings(settings);
}

if (!settings.Relays.Any())
{
settings.Relays.AddRange(_networkConfiguration.GetDefaultRelayUrls());
_networkStorage.SetSettings(settings);
}
}

public async Task CheckServices(bool force = false)
Expand Down

0 comments on commit bf242da

Please sign in to comment.