Skip to content

Commit ba4ec75

Browse files
authored
Merge pull request #4 from bmresearch/add-request-airdrop-non-mainnet
feat: ability to request airdrop when non-mainnet
2 parents 9fa9a5d + f940f53 commit ba4ec75

File tree

6 files changed

+102
-7
lines changed

6 files changed

+102
-7
lines changed

Anvil/Models/ApplicationState.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,30 @@ public string RpcUrl
2828
set => this.RaiseAndSetIfChanged(ref _rpcUrl, value);
2929
}
3030

31+
3132
[DataMember]
3233
private Cluster _cluster = Cluster.MainNet;
34+
35+
/// <summary>
36+
/// A setting used in order to choose which cluster to use as an RPC Client Provider.
37+
/// </summary>
3338
public Cluster Cluster
3439
{
3540
get => _cluster;
3641
set => this.RaiseAndSetIfChanged(ref _cluster, value);
3742
}
43+
44+
[DataMember]
45+
private Cluster _network = Cluster.MainNet;
46+
47+
/// <summary>
48+
/// A flag used in order to tag the current network according to the received genesis hash.
49+
/// </summary>
50+
public Cluster Network
51+
{
52+
get => _network;
53+
set => this.RaiseAndSetIfChanged(ref _network, value);
54+
}
3855

3956
[DataMember]
4057
private string _storePath = AppContext.BaseDirectory;

Anvil/ViewModels/Common/TransactionSubmissionViewModel.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,11 @@ public async void CopyTransactionHashToClipboard()
4444
/// Initialize the transaction submission.
4545
/// </summary>
4646
/// <param name="rpcClientProvider">The rpc client provider.</param>
47-
public TransactionSubmissionViewModel(IRpcClientProvider rpcClientProvider)
47+
/// <param name="transactionHash">The transaction hash.</param>
48+
public TransactionSubmissionViewModel(IRpcClientProvider rpcClientProvider, string transactionHash = null)
4849
{
4950
_rpcClientProvider = rpcClientProvider;
51+
TransactionHash = transactionHash;
5052
}
5153

5254
/// <summary>
@@ -56,6 +58,8 @@ public TransactionSubmissionViewModel(IRpcClientProvider rpcClientProvider)
5658
/// <returns>A task that performs the action and may return a boolean which represents whether it was a successful submission or not.</returns>
5759
public async Task<bool> SubmitTransaction(byte[] transaction)
5860
{
61+
if (TransactionHash != null) return false;
62+
5963
Progress = "Submitting transaction..";
6064
var txSig = await _rpcClientProvider.Client.SendTransactionAsync(transaction,
6165
commitment: Solnet.Rpc.Types.Commitment.Confirmed);

Anvil/ViewModels/MainWindowViewModel.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ private void _keyStoreService_OnStartupStateChanged(object sender, Services.Even
320320
if (!_keyStoreService.IsProcessing && KeyStoreServiceState == KeyStoreServiceState.Done)
321321
{
322322
_walletViewModel ??= new WalletViewModel(_appLifetime, _internetService, _walletService,
323-
_rpcProvider, _keyStoreService, _addressBookService);
323+
_rpcProvider, _keyStoreService, _addressBookService, _appState);
324324
CurrentView = _walletViewModel;
325325
WalletUnlocked = true;
326326
RestoreFromWalletSnapshot();
@@ -358,7 +358,7 @@ private async void OnWalletImport(WalletImport walletImport)
358358
// private key import
359359
await _keyStoreService.InitializeWalletWithPrivateKey(walletImport.PrivateKeyFilePath, walletImport.Alias, walletImport.Password);
360360

361-
_walletViewModel ??= new WalletViewModel(_appLifetime, _internetService, _walletService, _rpcProvider, _keyStoreService, _addressBookService);
361+
_walletViewModel ??= new WalletViewModel(_appLifetime, _internetService, _walletService, _rpcProvider, _keyStoreService, _addressBookService, _appState);
362362
CurrentView = _walletViewModel;
363363
WalletUnlocked = true;
364364
}
@@ -367,7 +367,7 @@ private async void OnWalletImport(WalletImport walletImport)
367367
// mnemonic import
368368
await _keyStoreService.InitializeWallet(walletImport.Mnemonic, walletImport.Password);
369369

370-
_walletViewModel ??= new WalletViewModel(_appLifetime, _internetService, _walletService, _rpcProvider, _keyStoreService, _addressBookService);
370+
_walletViewModel ??= new WalletViewModel(_appLifetime, _internetService, _walletService, _rpcProvider, _keyStoreService, _addressBookService, _appState);
371371
CurrentView = _walletViewModel;
372372
WalletUnlocked = true;
373373
}
@@ -393,7 +393,7 @@ public void ChangeView(string view)
393393
switch (view)
394394
{
395395
case "Wallet":
396-
_walletViewModel ??= new WalletViewModel(_appLifetime, _internetService, _walletService, _rpcProvider, _keyStoreService, _addressBookService);
396+
_walletViewModel ??= new WalletViewModel(_appLifetime, _internetService, _walletService, _rpcProvider, _keyStoreService, _addressBookService, _appState);
397397
CurrentView = _walletViewModel;
398398
break;
399399
case "WatchOnly":

Anvil/ViewModels/SettingsViewModel.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,29 @@ public SettingsViewModel(ApplicationState appState, IRpcClientProvider rpcClient
7575
GetVersionInfo();
7676
}
7777

78+
private async void GetNetworkInfo()
79+
{
80+
var g = await _rpcClientProvider.Client.GetGenesisHashAsync();
81+
82+
var cluster = GetClusterForBlockhash(g.Result);
83+
84+
_appState.Network = cluster;
85+
}
86+
87+
private Cluster GetClusterForBlockhash(string blockhash)
88+
{
89+
return blockhash switch
90+
{
91+
"5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d" => Cluster.MainNet,
92+
"4uhcVJyU9pJkvQyS88uRDiswHXSCkY3zQawwpjk2NsNY" => Cluster.TestNet,
93+
"EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG" => Cluster.DevNet,
94+
_ => Cluster.DevNet,
95+
};
96+
}
97+
7898
private async void GetVersionInfo()
7999
{
100+
80101
var v = await _rpcClientProvider.Client.GetVersionAsync();
81102

82103
if (v.WasRequestSuccessfullyHandled)
@@ -136,6 +157,7 @@ public void ApplyChanges()
136157
default:
137158
break;
138159
}
160+
GetNetworkInfo();
139161
GetVersionInfo();
140162
}
141163

Anvil/ViewModels/Wallet/WalletViewModel.cs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Anvil.Core.ViewModels;
2+
using Anvil.Models;
23
using Anvil.Services;
34
using Anvil.Services.Network;
45
using Anvil.Services.Wallets;
@@ -55,10 +56,13 @@ public class WalletViewModel : ViewModelBase
5556

5657
#endregion
5758

59+
private ApplicationState _appState;
60+
5861
public WalletViewModel(IClassicDesktopStyleApplicationLifetime appLifetime,
5962
InternetConnectionService internetConnectionService,
6063
IWalletService walletService, IRpcClientProvider rpcClientProvider,
61-
KeyStoreService keyStoreService, AddressBookService addressBookService)
64+
KeyStoreService keyStoreService, AddressBookService addressBookService,
65+
ApplicationState applicationState)
6266
{
6367
_appLifetime = appLifetime;
6468
_internetConnectionService = internetConnectionService;
@@ -70,9 +74,13 @@ public WalletViewModel(IClassicDesktopStyleApplicationLifetime appLifetime,
7074
_walletService.OnWalletServiceStateChanged += OnWalletServiceStateChanged;
7175
_keyStoreService = keyStoreService;
7276
_addressBookService = addressBookService;
77+
_appState = applicationState;
78+
79+
_appState.PropertyChanged += ApplicationStateChanged;
7380

7481
DerivationWalletsCollection = new();
7582
PrivateKeyWalletsCollection = new();
83+
CanRequestAirdrop = _appState.Network != Cluster.MainNet;
7684
NoConnection = !_internetConnectionService.IsConnected;
7785
TransactionSubmission = TransactionSubmissionViewModel.NoShow();
7886
TransactionSubmission.WhenAnyValue(x => x.SubmittingTransaction)
@@ -84,11 +92,36 @@ public WalletViewModel(IClassicDesktopStyleApplicationLifetime appLifetime,
8492
RestoreFromWalletSnapshot(false);
8593
}
8694

95+
private void ApplicationStateChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
96+
{
97+
if (e.PropertyName == "Network")
98+
{
99+
CanRequestAirdrop = _appState.Network != Cluster.MainNet;
100+
}
101+
}
102+
87103
private void OnNetworkConnectionChanged(object sender, Services.Network.Events.NetworkConnectionChangedEventArgs e)
88104
{
89105
NoConnection = !e.Connected;
90106
}
91107

108+
public async void RequestAirdrop()
109+
{
110+
var req = await _rpcClient.RequestAirdropAsync(_currentWallet.Address, SolHelper.ConvertToLamports(1m));
111+
if (req.WasSuccessful)
112+
{
113+
if(req.Result != null)
114+
{
115+
TransactionSubmission = new TransactionSubmissionViewModel(_rpcClientProvider, req.Result);
116+
TransactionSubmission.Progress = "Successfully requested airdrop.";
117+
await TransactionSubmission.PollConfirmation();
118+
await GetAccountBalance();
119+
await Task.Delay(15000);
120+
TransactionSubmission = TransactionSubmissionViewModel.NoShow();
121+
}
122+
}
123+
}
124+
92125
private async Task<SendSolanaDialogViewModel> GetDestinationAddressAndAmount()
93126
{
94127
var vm = new SendSolanaDialogViewModel()
@@ -330,7 +363,7 @@ private Tuple<bool, string> ValidateMnemonicDelegate(string text)
330363

331364
return new Tuple<bool, string>(false, "Mnemonic is invalid.");
332365
}
333-
366+
334367
/// <summary>
335368
/// Private key validation for the dialog.
336369
/// </summary>
@@ -784,6 +817,13 @@ private void UpdateTokenCollection()
784817
}
785818
}
786819

820+
private bool _canRequestAirdrop;
821+
public bool CanRequestAirdrop
822+
{
823+
get => _canRequestAirdrop;
824+
set => this.RaiseAndSetIfChanged(ref _canRequestAirdrop, value);
825+
}
826+
787827
private bool _canSubmitTransaction;
788828
public bool CanSubmitTransaction
789829
{

Anvil/Views/Wallet/WalletView.axaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,18 @@
304304
<avalonia:MaterialIcon Kind="Send" VerticalAlignment="Center"/>
305305
</StackPanel>
306306
</Button>
307+
<Button
308+
Command="{Binding RequestAirdrop}"
309+
VerticalAlignment="Center"
310+
HorizontalAlignment="Center"
311+
IsVisible="{Binding CanRequestAirdrop}"
312+
Margin="5"
313+
ToolTip.Tip="Request Airdrop">
314+
<StackPanel
315+
Orientation="Horizontal">
316+
<avalonia:MaterialIcon Kind="ArrowDownBold" VerticalAlignment="Center"/>
317+
</StackPanel>
318+
</Button>
307319
</StackPanel>
308320
<common:TransactionSubmissionView
309321
DockPanel.Dock="Top"

0 commit comments

Comments
 (0)