Skip to content

Commit

Permalink
Wallet: Implement recovery phrase page
Browse files Browse the repository at this point in the history
  • Loading branch information
dennisreimann committed Feb 12, 2025
1 parent 02e5f96 commit c1dce9f
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 34 deletions.
2 changes: 1 addition & 1 deletion BTCPayApp.UI/Pages/Settings/IndexPage.razor
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@
}
</div>
</li>
@if (State.Value.ConnectionState != BTCPayConnectionState.ConnectedAsSlave)
@if (State.Value.ConnectionState == BTCPayConnectionState.ConnectedAsMaster)
{
<li class="list-group-item">
<div class="justify-content-start">
Expand Down
38 changes: 16 additions & 22 deletions BTCPayApp.UI/Pages/Wallet/SeedPage.razor
Original file line number Diff line number Diff line change
@@ -1,47 +1,41 @@
@attribute [Route(Routes.WalletSeed)]
@using BTCPayApp.UI.Features
@using BTCPayApp.Core.Auth
@using BTCPayApp.Core.Data
@using BTCPayApp.Core.Wallet
@using BTCPayApp.UI.Components.Layout
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
@inject OnChainWalletManager OnChainWalletManager
@inject IState<RootState> State

<PageTitle>@GetTitle()</PageTitle>
<PageTitle>Secure your recovery phrase</PageTitle>

<SectionContent SectionId="_Layout.Top">
<Titlebar Back>
<h1>@GetTitle()</h1>
<h1>Secure your recovery phrase</h1>
</Titlebar>
</SectionContent>

<section class="container">
<AuthorizeView Policy="@AppPolicies.CanModifySettings">
<Authorized>
@if (State.Value.OnchainWalletState == OnChainWalletState.Loaded && Config is not null)
@if (Words is not null)
{
<h2>Wallet</h2>
<div class="box">
<ol class="m-0 pt-4 ms-3">
@foreach (var word in Config.Mnemonic.Split(' '))
<p>
The combination of words below are called your recovery phrase.
The recovery phrase allows you to access and restore your wallet.
</p>
<p class="text-warning">
Anyone who knows it can access your funds.
Write them down on a piece of paper in this exact order.
</p>
<div class="box my-4">
<ol class="seed">
@foreach (var word in Words)
{
<li class="font-monospace">@word</li>
<li>@word</li>
}
</ol>
</div>
}
else
{
<p>
@(State.Value.OnchainWalletState switch
{
OnChainWalletState.NotConfigured => "Not configured",
OnChainWalletState.WaitingForConnection => "Waiting for connection",
_ => State.Value.OnchainWalletState.ToString()
})
</p>
}
</Authorized>
<NotAuthorized>
<Alert Type="danger">Unauthorized.</Alert>
Expand All @@ -59,6 +53,6 @@

private WalletConfig? Config { get; set; }

private string GetTitle() => "Secure your recovery phrase";
private string[]? Words => Config?.Mnemonic.Split(' ');
}

22 changes: 22 additions & 0 deletions BTCPayApp.UI/Pages/Wallet/SeedPage.razor.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.container {
max-width: 500px;
}

.seed {
display: grid;
grid-auto-flow: column;
grid-template-rows: repeat(6, auto);
gap: var(--btcpay-space-m);
justify-content: space-evenly;
padding: 0;
}

.seed li::marker {
color: var(--btcpay-body-text-muted);
font-weight: var(--btcpay-font-weight-normal);
padding-left: 2em;
}

.seed li {
font-weight: var(--btcpay-font-weight-semibold);
}
33 changes: 22 additions & 11 deletions BTCPayApp.UI/Pages/Wallet/SettingsPage.razor
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@
{
<Alert Type="success" Dismissible>@_successMessage</Alert>
}
@if (State.Value.OnchainWalletState == OnChainWalletState.Loaded && Derivation is not null)
@if (OnChainWalletManager.IsActive)
{
var descriptor = Derivation.Descriptor;
if (Derivation is null) return;
var descriptor = Derivation!.Descriptor;
var isStorePM = IsStorePaymentMethodId(Derivation.Identifier!);
<header class="d-flex align-items-center justify-content-between gap-3 mb-3">
<h2 class="mb-0">@Derivation.Name</h2>
Expand All @@ -49,7 +50,7 @@
</header>
<div class="box mb-2">
<div class="form-floating">
<TruncateCenter Text="@Config.Fingerprint" Padding="15" Copy="true" Elastic="true" class="form-control-plaintext"/>
<TruncateCenter Text="@Config!.Fingerprint" Padding="15" Copy="true" Elastic="true" class="form-control-plaintext"/>
<label>Fingerprint</label>
</div>
@if (!string.IsNullOrEmpty(Derivation.Identifier))
Expand Down Expand Up @@ -78,28 +79,28 @@
<li class="list-group-item">
<a href="@Routes.WalletSeed">
<Icon Symbol="wallet-seed"/>
<span>Recovery Phrase</span>
<span>Your Recovery Phrase</span>
<Icon Symbol="caret-right"/>
</a>
</li>
</ul>
</div>
}
else if (State.Value.ConnectionState == BTCPayConnectionState.ConnectedAsMaster)
{
<button class="btn btn-primary" @onclick="GenerateWallet">Generate wallet</button>
}
else
{
<p>
@(State.Value.OnchainWalletState switch
@(OnChainWalletManager.State switch
{
OnChainWalletState.NotConfigured => "Not configured",
OnChainWalletState.WaitingForConnection => "Waiting for connection",
_ => State.Value.OnchainWalletState.ToString()
})
</p>
}
@if (_canConfigureWallet)
{
<button class="btn btn-primary" @onclick="GenerateWallet">Generate wallet</button>
}
</Authorized>
<NotAuthorized>
<Alert Type="danger">Unauthorized.</Alert>
Expand All @@ -113,17 +114,19 @@
private string? _storePaymentMethodIdentifier;
private string? _errorMessage;
private string? _successMessage;
private bool _canConfigureWallet;

private WalletConfig? Config { get; set; }
private WalletDerivation? Derivation => Config?.Derivations.FirstOrDefault(d => d.Key == WalletDerivation.NativeSegwit).Value;
private WalletDerivation? Derivation { get; set; }

protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();

if (!string.IsNullOrEmpty(StoreId))
await GetStorePaymentMethod();
Config = await OnChainWalletManager.GetConfig();

await SetupWallet();
}

private async Task GetStorePaymentMethod()
Expand All @@ -140,6 +143,13 @@
}
}

private async Task SetupWallet()
{
Config = await OnChainWalletManager.GetConfig();
Derivation = Config?.Derivations.FirstOrDefault(d => d.Key == WalletDerivation.NativeSegwit).Value;
_canConfigureWallet = await OnChainWalletManager.CanConfigureWallet();
}

private async Task SetStorePaymentMethod()
{
if (string.IsNullOrEmpty(StoreId) || Derivation?.Descriptor is null) return;
Expand Down Expand Up @@ -168,6 +178,7 @@
await AsyncExtensions.RunInOtherThread(async () =>
{
await OnChainWalletManager.Generate();
await SetupWallet();
});
}

Expand Down

0 comments on commit c1dce9f

Please sign in to comment.