From 92fa21b1c33f5292d3b105c257bc7c4c056c9fff Mon Sep 17 00:00:00 2001 From: dangershony Date: Sun, 17 Dec 2023 00:22:21 +0000 Subject: [PATCH] Create a faucet for the signet --- src/Angor/Client/Pages/Wallet.razor | 29 ++++++ src/Angor/Server/FaucetController.cs | 142 +++++++++++++++++++++++++++ src/Angor/Server/Program.cs | 6 ++ 3 files changed, 177 insertions(+) create mode 100644 src/Angor/Server/FaucetController.cs diff --git a/src/Angor/Client/Pages/Wallet.razor b/src/Angor/Client/Pages/Wallet.razor index 8385a308..c6b62bce 100644 --- a/src/Angor/Client/Pages/Wallet.razor +++ b/src/Angor/Client/Pages/Wallet.razor @@ -7,6 +7,7 @@ @using Angor.Shared.Models @using Angor.Client.Components +@inject HttpClient _httpClient; @inject IClientStorage storage; @inject IWalletStorage _walletStorage; @inject ILogger Logger; @@ -164,6 +165,9 @@

Receive Address

@nextReceiveAddress

+ + + @@ -660,4 +664,29 @@ coinControlModal = true; StateHasChanged(); } + + private async Task GetTestCoins() + { + if (localAccountInfo.TotalBalance > 10) + { + notificationComponent.ShowNotificationMessage("you already have coins!"); + } + + var operationResult = await notificationComponent.LongOperation(async () => + { + + var res = await _httpClient.GetAsync($"/api/faucet/send/{localAccountInfo.GetNextReceiveAddress()}"); + + if (res.IsSuccessStatusCode) + return new OperationResult { Success = true }; + + return new OperationResult { Success = false,Message = await res.Content.ReadAsStringAsync()}; + }); + + if (operationResult is { Success: true }) + { + notificationComponent.ShowNotificationMessage("Success!"); + } + } + } \ No newline at end of file diff --git a/src/Angor/Server/FaucetController.cs b/src/Angor/Server/FaucetController.cs new file mode 100644 index 00000000..778c1ad9 --- /dev/null +++ b/src/Angor/Server/FaucetController.cs @@ -0,0 +1,142 @@ +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 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 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 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(); + } + + 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 SettingsUrl GetPrimaryIndexer() + { + return new SettingsUrl { Url = "https://tbtc.indexer.angor.io" }; + } + + public SettingsUrl GetPrimaryRelay() + { + throw new NotImplementedException(); + } + + public List GetRelays() + { + throw new NotImplementedException(); + } + + public void CheckAndHandleError(HttpResponseMessage httpResponseMessage) + { + + } + + public void HandleException(Exception exception) + { + throw exception; + } + } +} \ No newline at end of file diff --git a/src/Angor/Server/Program.cs b/src/Angor/Server/Program.cs index a5952e37..6632dbf8 100644 --- a/src/Angor/Server/Program.cs +++ b/src/Angor/Server/Program.cs @@ -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); @@ -20,7 +22,11 @@ // types needed to build investor sigs builder.Services.AddSingleton(); +builder.Services.AddSingleton(); builder.Services.AddSingleton(); +builder.Services.AddSingleton(); +builder.Services.AddSingleton(); +builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton();