diff --git a/Chia_Coin_Inspector.sln b/Chia_Coin_Inspector.sln
new file mode 100644
index 0000000..52bea6e
--- /dev/null
+++ b/Chia_Coin_Inspector.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.9.34728.123
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Chia_Coin_Inspector", "Chia_Coin_Inspector\Chia_Coin_Inspector.csproj", "{C0AEFAC3-8447-472E-9D74-41AC1D0B961C}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C0AEFAC3-8447-472E-9D74-41AC1D0B961C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C0AEFAC3-8447-472E-9D74-41AC1D0B961C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C0AEFAC3-8447-472E-9D74-41AC1D0B961C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C0AEFAC3-8447-472E-9D74-41AC1D0B961C}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {C3658570-2A64-439E-9F19-527355639A6D}
+ EndGlobalSection
+EndGlobal
diff --git a/Chia_Coin_Inspector/Chia_Coin_Inspector.csproj b/Chia_Coin_Inspector/Chia_Coin_Inspector.csproj
new file mode 100644
index 0000000..5a4f50a
--- /dev/null
+++ b/Chia_Coin_Inspector/Chia_Coin_Inspector.csproj
@@ -0,0 +1,16 @@
+
+
+
+ WinExe
+ net8.0-windows
+ enable
+ true
+ enable
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Chia_Coin_Inspector/Form1.Designer.cs b/Chia_Coin_Inspector/Form1.Designer.cs
new file mode 100644
index 0000000..29c7a56
--- /dev/null
+++ b/Chia_Coin_Inspector/Form1.Designer.cs
@@ -0,0 +1,171 @@
+namespace Chia_Coin_Inspector
+{
+ partial class Form1
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
+ System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
+ System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();
+ walletList = new ListBox();
+ chart1 = new System.Windows.Forms.DataVisualization.Charting.Chart();
+ XCHlbl = new Label();
+ Coinslbl = new Label();
+ chiarecords = new DataGridView();
+ blockstatuslbl = new Label();
+ Refreshbtn = new Button();
+ nftImage = new PictureBox();
+ ((System.ComponentModel.ISupportInitialize)chart1).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)chiarecords).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)nftImage).BeginInit();
+ SuspendLayout();
+ //
+ // walletList
+ //
+ walletList.FormattingEnabled = true;
+ walletList.ItemHeight = 15;
+ walletList.Location = new Point(3, 920);
+ walletList.Name = "walletList";
+ walletList.Size = new Size(218, 94);
+ walletList.TabIndex = 1;
+ walletList.SelectedIndexChanged += walletList_SelectedIndexChanged;
+ //
+ // chart1
+ //
+ chartArea1.Name = "ChartArea1";
+ chart1.ChartAreas.Add(chartArea1);
+ legend1.Name = "Legend1";
+ chart1.Legends.Add(legend1);
+ chart1.Location = new Point(227, 920);
+ chart1.Name = "chart1";
+ series1.ChartArea = "ChartArea1";
+ series1.ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Pie;
+ series1.IsValueShownAsLabel = true;
+ series1.IsVisibleInLegend = false;
+ series1.Legend = "Legend1";
+ series1.Name = "Fragmentation";
+ chart1.Series.Add(series1);
+ chart1.Size = new Size(1070, 252);
+ chart1.TabIndex = 2;
+ chart1.Text = "Coin Fragmentation";
+ //
+ // XCHlbl
+ //
+ XCHlbl.AutoSize = true;
+ XCHlbl.Location = new Point(3, 1096);
+ XCHlbl.Name = "XCHlbl";
+ XCHlbl.Size = new Size(0, 15);
+ XCHlbl.TabIndex = 3;
+ //
+ // Coinslbl
+ //
+ Coinslbl.AutoSize = true;
+ Coinslbl.Location = new Point(3, 1129);
+ Coinslbl.Name = "Coinslbl";
+ Coinslbl.Size = new Size(0, 15);
+ Coinslbl.TabIndex = 4;
+ //
+ // chiarecords
+ //
+ chiarecords.AllowUserToAddRows = false;
+ chiarecords.AllowUserToDeleteRows = false;
+ chiarecords.AllowUserToOrderColumns = true;
+ chiarecords.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+ chiarecords.EditMode = DataGridViewEditMode.EditProgrammatically;
+ chiarecords.Location = new Point(3, 58);
+ chiarecords.MultiSelect = false;
+ chiarecords.Name = "chiarecords";
+ chiarecords.ReadOnly = true;
+ chiarecords.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
+ chiarecords.Size = new Size(1294, 158);
+ chiarecords.TabIndex = 6;
+ chiarecords.TabStop = false;
+ chiarecords.MouseDown += chiarecords_MouseDown;
+ //
+ // blockstatuslbl
+ //
+ blockstatuslbl.AutoSize = true;
+ blockstatuslbl.Location = new Point(3, 40);
+ blockstatuslbl.Name = "blockstatuslbl";
+ blockstatuslbl.Size = new Size(38, 15);
+ blockstatuslbl.TabIndex = 8;
+ blockstatuslbl.Text = "label1";
+ //
+ // Refreshbtn
+ //
+ Refreshbtn.Location = new Point(3, 7);
+ Refreshbtn.Name = "Refreshbtn";
+ Refreshbtn.Size = new Size(75, 23);
+ Refreshbtn.TabIndex = 10;
+ Refreshbtn.Text = "Refresh";
+ Refreshbtn.UseVisualStyleBackColor = true;
+ Refreshbtn.Click += Refreshbtn_Click;
+ //
+ // nftImage
+ //
+ nftImage.Location = new Point(3, 222);
+ nftImage.Name = "nftImage";
+ nftImage.Size = new Size(1294, 692);
+ nftImage.SizeMode = PictureBoxSizeMode.CenterImage;
+ nftImage.TabIndex = 11;
+ nftImage.TabStop = false;
+ //
+ // Form1
+ //
+ AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleMode = AutoScaleMode.Font;
+ ClientSize = new Size(1300, 1184);
+ Controls.Add(nftImage);
+ Controls.Add(Refreshbtn);
+ Controls.Add(blockstatuslbl);
+ Controls.Add(chiarecords);
+ Controls.Add(chart1);
+ Controls.Add(Coinslbl);
+ Controls.Add(XCHlbl);
+ Controls.Add(walletList);
+ Name = "Form1";
+ Text = "Form1";
+ Load += Form1_Load;
+ ((System.ComponentModel.ISupportInitialize)chart1).EndInit();
+ ((System.ComponentModel.ISupportInitialize)chiarecords).EndInit();
+ ((System.ComponentModel.ISupportInitialize)nftImage).EndInit();
+ ResumeLayout(false);
+ PerformLayout();
+ }
+
+ #endregion
+ private ListBox walletList;
+ private System.Windows.Forms.DataVisualization.Charting.Chart chart1;
+ private Label XCHlbl;
+ private Label Coinslbl;
+ private Button button1;
+ private DataGridView chiarecords;
+ private Label blockstatuslbl;
+ private Button Refreshbtn;
+ private PictureBox nftImage;
+ }
+}
diff --git a/Chia_Coin_Inspector/Form1.cs b/Chia_Coin_Inspector/Form1.cs
new file mode 100644
index 0000000..e12c52a
--- /dev/null
+++ b/Chia_Coin_Inspector/Form1.cs
@@ -0,0 +1,237 @@
+using chia.dotnet;
+using System.Data;
+using System.Net;
+
+namespace Chia_Coin_Inspector
+{
+ public partial class Form1 : Form
+ {
+ public Form1()
+ {
+ InitializeComponent();
+ }
+
+ public uint peakheightstart;
+ public uint peakheightend;
+ public uint blocksperday = 4608;
+ public uint nftWalletID = 0;
+
+ private void Form1_Load(object sender, EventArgs e)
+ {
+ RefreshPageLoad();
+ }
+
+ private async void RefreshPageLoad()
+ {
+ var endpoint = Config.Open().GetEndpoint("wallet");
+ using (var rpcClient = new HttpRpcClient(endpoint))
+ {
+ var wallet = new WalletProxy(rpcClient, "test");
+ var wallets = await wallet.GetWallets();
+ foreach (WalletInfo info in wallets.Wallets)
+ {
+ walletList.Items.Add(info.Id);
+ if (info.Type == WalletType.NFT)
+ {
+ nftWalletID = info.Id;
+ }
+ }
+ if (nftWalletID > 0)
+ {
+ var nftwallet = new NFTWallet(nftWalletID, wallet);
+ var nftcount = await nftwallet.CountNFTs();
+ var nfts = await nftwallet.GetNFTs(0, nftcount);
+ chiarecords.DataSource = nfts;
+ blockstatuslbl.Text = "";
+ chiarecords.ClearSelection();
+ }
+ }
+ }
+
+ private async void walletList_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ XCHlbl.Text = "";
+ Coinslbl.Text = "";
+ foreach (var series in chart1.Series)
+ {
+ series.Points.Clear();
+ }
+ if (walletList.SelectedIndex != -1)
+ {
+ List wallet_ids = new List();
+ var endpoint = Config.Open().GetEndpoint("wallet");
+ double mojo = 1000000000000;
+ using (var rpcClient = new HttpRpcClient(endpoint))
+ {
+ var wallet = new WalletProxy(rpcClient, "test");
+ wallet_ids.Add((uint)walletList.SelectedItem);
+ var wallets = await wallet.GetWallets();
+ var balances = await wallet.GetWalletBalances(wallet_ids);
+ string catname = "XCH";
+ foreach (var balance in balances)
+ {
+ if (balance.Value.WalletType.ToString() == "CAT" && !string.IsNullOrEmpty(balance.Value.AssetId))
+ {
+ var catwallet = new CATWallet(balance.Value.WalletId, wallet);
+ catname = await catwallet.GetName();
+ XCHlbl.Text = (decimal)((double)balance.Value.ConfirmedWalletBalance / mojo) + " " + catname;
+ }
+ else
+ {
+ XCHlbl.Text = (decimal)((double)balance.Value.ConfirmedWalletBalance / mojo) + " " + catname;
+ }
+ if (balance.Value.ConfirmedWalletBalance != 0)
+ {
+ var mywallet = new Wallet(balance.Value.WalletId, wallet);
+ var coins = await mywallet.GetSpendableCoins(0, 0);
+ int x = 0;
+ int y = 0;
+ chart1.Series["Fragmentation"].IsValueShownAsLabel = true;
+ foreach (var coin in coins.ConfirmedRecords)
+ {
+ x++;
+ if (Math.Round(((double)coin.Coin.Amount) / mojo, 3) > 0)
+ {
+ chart1.Series["Fragmentation"].Points.AddXY(x, Math.Round(((double)coin.Coin.Amount) / mojo, 3));
+ }
+ else
+ {
+ chart1.Series["Fragmentation"].Points.AddXY(x, (decimal)(((double)coin.Coin.Amount) / mojo));
+ chart1.Series["Fragmentation"].IsValueShownAsLabel = false;
+ }
+ chart1.Series["Fragmentation"].Points[y].ToolTip = (decimal)(((double)coin.Coin.Amount) / mojo) + " " + catname + Environment.NewLine + coin.Coin.Amount.ToString() + " Mojos";
+ y++;
+ }
+ Coinslbl.Text = x.ToString() + " Coins";
+ }
+ }
+ }
+ }
+ }
+
+ public void ClearDataGridView(DataGridView view)
+ {
+ while (view.DataSource != null)
+ {
+ view.DataSource = null;
+ }
+ view.Columns.Clear();
+ view.Rows.Clear();
+ }
+
+ private async void chiarecords_MouseDown(object sender, MouseEventArgs e)
+ {
+ var cancelSource = new CancellationTokenSource();
+ var hti = chiarecords.HitTest(e.X, e.Y);
+ List records = new List();
+ if (hti.RowIndex < 0 || hti.ColumnIndex < 0)
+ {
+ return;
+ }
+ if (chiarecords.Rows.Count <= hti.RowIndex) return;
+ if (!chiarecords[hti.ColumnIndex, hti.RowIndex].Selected)
+ {
+ chiarecords.ClearSelection();
+ chiarecords[hti.ColumnIndex, hti.RowIndex].Selected = true;
+ }
+ int[] selectedrows = chiarecords.SelectedRows.Cast().Select(x => x.Index).Distinct().ToArray();
+ if (selectedrows.Length > 0)
+ {
+ var endpoint = Config.Open().GetEndpoint("wallet");
+ using (var rpcClient = new HttpRpcClient(endpoint))
+ {
+ var wallet = new WalletProxy(rpcClient, "test");
+ foreach (int c in selectedrows)
+ {
+ if (nftWalletID > 0)
+ {
+ var nftwallet = new NFTWallet(nftWalletID, wallet);
+ var nfts = await nftwallet.GetNFTs(c, 1);
+ foreach (NFTInfo info in nfts)
+ {
+ bool redirected = false;
+ string url = "";
+ foreach (string uri in info.DataUris)
+ {
+ if (uri.StartsWith("http"))
+ {
+ url = uri;
+ blockstatuslbl.Text = "Downloading NFT image...";
+ Tuple retval = await downLoadImage(uri, false);
+ if (retval.Item1 == 1) break;
+ if (retval.Item1 == 2)
+ {
+ redirected = true;
+ }
+ blockstatuslbl.Text = "";
+ }
+ }
+ if (redirected)
+ {
+ Tuple retval = await downLoadImage(url, true);
+ if (retval.Item1 == 1)
+ {
+ DialogResult diagResult = MessageBox.Show("The image associated with this NFT has been moved to a new location. Would you like to update the URL in your NFT metadata? (NOTE: If this NFT image is displaying properly in your Chia wallet, no action is required)" + Environment.NewLine + Environment.NewLine + "Old URL: " + url + Environment.NewLine + "New URL: " + retval.Item2, "Modify URL", MessageBoxButtons.YesNo);
+ if (diagResult == DialogResult.Yes)
+ {
+ await nftwallet.AddUri(retval.Item2, "u", info.NFTCoinID, null, 0, cancelSource.Token);
+ }
+ }
+ }
+ }
+ blockstatuslbl.Text = "";
+ }
+ }
+ }
+ }
+ }
+
+ private void Refreshbtn_Click(object sender, EventArgs e)
+ {
+ RefreshPageLoad();
+ }
+
+ public async Task> downLoadImage(string url, bool redirect)
+ {
+ var handler = new HttpClientHandler()
+ {
+ AllowAutoRedirect = redirect
+ };
+ using (var client = new HttpClient(handler))
+ {
+ var response = client.GetAsync(url).Result;
+ if (response != null && response.StatusCode == HttpStatusCode.OK)
+ {
+
+ using (var stream = await response.Content.ReadAsStreamAsync())
+ {
+ using (var memStream = new MemoryStream())
+ {
+ await stream.CopyToAsync(memStream);
+ memStream.Position = 0;
+ nftImage.Image = Bitmap.FromStream(memStream);
+ }
+ }
+ if (redirect)
+ {
+ return Tuple.Create(1, response.RequestMessage.RequestUri.ToString());
+ }
+ else
+ {
+ return Tuple.Create(1, url);
+ }
+ }
+ else if (response != null && response.StatusCode == HttpStatusCode.MovedPermanently)
+ {
+ nftImage.Image = null;
+ return Tuple.Create(2, url);
+ }
+ else
+ {
+ nftImage.Image = null;
+ return Tuple.Create(3, url);
+ }
+ }
+ }
+ }
+}
diff --git a/Chia_Coin_Inspector/Form1.resx b/Chia_Coin_Inspector/Form1.resx
new file mode 100644
index 0000000..af32865
--- /dev/null
+++ b/Chia_Coin_Inspector/Form1.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Chia_Coin_Inspector/Program.cs b/Chia_Coin_Inspector/Program.cs
new file mode 100644
index 0000000..e535a1a
--- /dev/null
+++ b/Chia_Coin_Inspector/Program.cs
@@ -0,0 +1,17 @@
+namespace Chia_Coin_Inspector
+{
+ internal static class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ static void Main()
+ {
+ // To customize application configuration such as set high DPI settings or default font,
+ // see https://aka.ms/applicationconfiguration.
+ ApplicationConfiguration.Initialize();
+ Application.Run(new Form1());
+ }
+ }
+}
\ No newline at end of file