diff --git a/src/ArweaveAO/AODataClient.cs b/src/ArweaveAO/AODataClient.cs deleted file mode 100644 index 365130b..0000000 --- a/src/ArweaveAO/AODataClient.cs +++ /dev/null @@ -1,44 +0,0 @@ -using ArweaveAO.Models; -using ArweaveAO.Requests; -using ArweaveAO.Responses; -using System.Diagnostics; - -namespace ArweaveAO -{ - public class AODataClient : ClientAPI - { - public AODataClient(HttpClient http) : base("https://cu.ao-testnet.xyz", http) { } - public AODataClient(string baseRoute, HttpClient http) : base(baseRoute, http) { } - - public async Task DryRun(string processId, DryRunRequest request) - { - try - { - var result = await PostAsync($"dry-run?process-id={processId}", request); - return result; - - } - catch (Exception e) - { - // Deal with exception - throw; - } - } - - public async Task GetResult(string processId, string msgId) - { - try - { - var result = await GetAsync($"result/{msgId}?process-id={processId}"); - return result; - - } - catch (Exception e) - { - // Deal with exception - throw; - } - } - - } -} diff --git a/src/ArweaveAO/ArweaveAO.csproj b/src/ArweaveAO/ArweaveAO.csproj deleted file mode 100644 index f3a3135..0000000 --- a/src/ArweaveAO/ArweaveAO.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - net8.0 - enable - enable - nullable - - - - - - - diff --git a/src/ArweaveAO/ClientAPI.cs b/src/ArweaveAO/ClientAPI.cs deleted file mode 100644 index f90f45a..0000000 --- a/src/ArweaveAO/ClientAPI.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http.Json; -using System.Text; -using System.Threading.Tasks; - -namespace ArweaveAO -{ - public abstract class ClientAPI - { - protected readonly HttpClient Http; - private readonly string BaseRoute; - - protected ClientAPI(string baseRoute, HttpClient http) - { - BaseRoute = baseRoute; - Http = http; - } - - protected async Task GetAsync(string relativeUri) - { - HttpResponseMessage res = await Http.GetAsync($"{BaseRoute}/{relativeUri}"); - if (res.IsSuccessStatusCode) - { - return await res.Content.ReadFromJsonAsync(); - } - else - { - string msg = await res.Content.ReadAsStringAsync(); - Console.WriteLine(msg); - throw new Exception(msg); - } - } - - protected async Task PostAsync(string relativeUri, TRequest request) - { - HttpResponseMessage res = await Http.PostAsJsonAsync($"{BaseRoute}/{relativeUri}", request); - if (res.IsSuccessStatusCode) - { - return await res.Content.ReadFromJsonAsync(); - } - else - { - string msg = await res.Content.ReadAsStringAsync(); - Console.WriteLine(msg); - throw new Exception(msg); - } - } - } -} diff --git a/src/ArweaveAO/Models/Tag.cs b/src/ArweaveAO/Models/Tag.cs deleted file mode 100644 index 108c043..0000000 --- a/src/ArweaveAO/Models/Tag.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Text.Json.Serialization; -using System.Threading.Tasks; - -namespace ArweaveAO.Models -{ - [DebuggerDisplay("{Name}: {Value}")] - public class Tag - { - [JsonPropertyName("name")] - public required string Name { get; set; } - - [JsonPropertyName("value")] - public required string Value { get; set; } - } -} diff --git a/src/ArweaveAO/Models/Token/BalanceData.cs b/src/ArweaveAO/Models/Token/BalanceData.cs deleted file mode 100644 index 166f37a..0000000 --- a/src/ArweaveAO/Models/Token/BalanceData.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ArweaveAO.Models.Token -{ - public class BalanceData - { - public string? TokenId { get; set; } - public string? Account { get; set; } - public long? Balance { get; set; } - public string? Ticker { get; set; } - } -} diff --git a/src/ArweaveAO/Models/Token/TokenData.cs b/src/ArweaveAO/Models/Token/TokenData.cs deleted file mode 100644 index 154ff32..0000000 --- a/src/ArweaveAO/Models/Token/TokenData.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace ArweaveAO.Models.Token -{ - public class TokenData - { - public string? TokenId { get; set; } - public string? Name { get; set; } - public string? Ticker { get; set; } - public string? Logo { get; set; } - public int? Denomination { get; set; } - } -} diff --git a/src/ArweaveAO/Requests/DryRunRequest.cs b/src/ArweaveAO/Requests/DryRunRequest.cs deleted file mode 100644 index 62e322b..0000000 --- a/src/ArweaveAO/Requests/DryRunRequest.cs +++ /dev/null @@ -1,32 +0,0 @@ -using ArweaveAO.Models; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.Json.Serialization; -using System.Threading.Tasks; - -namespace ArweaveAO.Requests -{ - public class DryRunRequest - { - [JsonPropertyName("Id")] - public string? Id { get; set; } = "0000000000000000000000000000000000000000001"; - - [JsonPropertyName("Target")] - public required string Target { get; set; } - - [JsonPropertyName("Owner")] - public string Owner { get; set; } = "0000000000000000000000000000000000000000001"; - - [JsonPropertyName("Anchor")] - public string Anchor { get; set; } = "0"; - - [JsonPropertyName("Data")] - public string? Data { get; set; } - - [JsonPropertyName("Tags")] - public List Tags { get; set; } = new(); - } - -} diff --git a/src/ArweaveAO/Responses/MessageResult.cs b/src/ArweaveAO/Responses/MessageResult.cs deleted file mode 100644 index 3576873..0000000 --- a/src/ArweaveAO/Responses/MessageResult.cs +++ /dev/null @@ -1,35 +0,0 @@ -using ArweaveAO.Models; -using System.Text.Json.Serialization; - -namespace ArweaveAO.Responses -{ - public class MessageResult - { - [JsonPropertyName("Messages")] - public List Messages { get; set; } = new(); - - //[JsonPropertyName("Spawns")] - //public List Spawns { get; set; } - - //[JsonPropertyName("Output")] - //public List Output { get; set; } - - //[JsonPropertyName("GasUsed")] - //public int GasUsed { get; set; } - } - - public class Message - { - [JsonPropertyName("Target")] - public string? Target { get; set; } - - [JsonPropertyName("Anchor")] - public string? Anchor { get; set; } - - [JsonPropertyName("Data")] - public string? Data { get; set; } - - [JsonPropertyName("Tags")] - public List Tags { get; set; } = new(); - } -} diff --git a/src/ArweaveAO/TokenClient.cs b/src/ArweaveAO/TokenClient.cs deleted file mode 100644 index 0236ee4..0000000 --- a/src/ArweaveAO/TokenClient.cs +++ /dev/null @@ -1,94 +0,0 @@ -using ArweaveAO.Models; -using ArweaveAO.Models.Token; -using ArweaveAO.Requests; - -namespace ArweaveAO -{ - /// - /// TokenClient, helper to interact with processes implementing the ao token standard - /// - public class TokenClient : AODataClient - { - public TokenClient(HttpClient http) : base("https://cu.ao-testnet.xyz", http) { } - - public async Task GetTokenMetaData(string processId) - { - try - { - var request = new DryRunRequest - { - Target = processId, - Tags = new List - { - new Tag { Name = "Action", Value = "Info"}, - new Tag { Name = "Type", Value = "Message"}, - new Tag { Name = "Variant", Value = "ao.TN.1"}, - new Tag { Name = "Protocol", Value = "ao"}, - } - }; - var result = await DryRun(processId, request); - if (result == null || !result.Messages.Any()) - return null; - - var tokenData = new TokenData(); - tokenData.TokenId = processId; - tokenData.Name = result.Messages.First().Tags.Where(x => x.Name == "Name").Select(x => x.Value).FirstOrDefault(); - tokenData.Ticker = result.Messages.First().Tags.Where(x => x.Name == "Ticker").Select(x => x.Value).FirstOrDefault(); - tokenData.Logo = result.Messages.First().Tags.Where(x => x.Name == "Logo").Select(x => x.Value).FirstOrDefault(); - - - string? denomination = result.Messages.First().Tags.Where(x => x.Name == "Denomination").Select(x => x.Value).FirstOrDefault(); - if(!string.IsNullOrWhiteSpace(denomination) && int.TryParse(denomination, out int denominationInt)) - tokenData.Denomination = denominationInt; - - return tokenData; - } - catch (Exception e) - { - if (e.Message.Contains("not found", StringComparison.InvariantCultureIgnoreCase)) - return null; - - // Deal with exception - throw; - } - } - - public async Task GetBalance(string tokenId, string address) - { - try - { - var request = new DryRunRequest - { - Target = tokenId, - Tags = new List - { - new Tag { Name = "Action", Value = "Balance"}, - new Tag { Name = "Target", Value = address}, - new Tag { Name = "Type", Value = "Message"}, - new Tag { Name = "Variant", Value = "ao.TN.1"}, - new Tag { Name = "Protocol", Value = "ao"}, - } - }; - var result = await DryRun(tokenId, request); - if (result == null || !result.Messages.Any()) - return null; - - var balanceData = new BalanceData(); - balanceData.TokenId = tokenId; - balanceData.Ticker = result.Messages.First().Tags.Where(x => x.Name == "Ticker").Select(x => x.Value).FirstOrDefault(); - balanceData.Account = result.Messages.First().Tags.Where(x => x.Name == "Account").Select(x => x.Value).FirstOrDefault(); - - string? balance = result.Messages.First().Tags.Where(x => x.Name == "Balance").Select(x => x.Value).FirstOrDefault(); - if (!string.IsNullOrWhiteSpace(balance) && long.TryParse(balance, out long balanceLong)) - balanceData.Balance = balanceLong; - - return balanceData; - } - catch (Exception e) - { - // Deal with exception - throw; - } - } - } -} diff --git a/src/ArweaveBlazor/ArweaveBlazor.csproj b/src/ArweaveBlazor/ArweaveBlazor.csproj deleted file mode 100644 index 076997b..0000000 --- a/src/ArweaveBlazor/ArweaveBlazor.csproj +++ /dev/null @@ -1,29 +0,0 @@ - - - - net8.0 - enable - nullable - True - True - snupkg - Michiel Post - 0.0.1 - ArweaveBlazor - https://github.com/michielpost/ArweaveBlazor - https://github.com/michielpost/ArweaveBlazor - github - arweave blockchain web3 blazor - Arweave Blazor Extension - - - - - - - - - - - - diff --git a/src/ArweaveBlazor/ArweaveService.cs b/src/ArweaveBlazor/ArweaveService.cs deleted file mode 100644 index c1a2490..0000000 --- a/src/ArweaveBlazor/ArweaveService.cs +++ /dev/null @@ -1,143 +0,0 @@ -using ArweaveBlazor.Models; -using Microsoft.JSInterop; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading.Tasks; -using static System.Runtime.InteropServices.JavaScript.JSType; - -namespace ArweaveBlazor -{ - // This class provides an example of how JavaScript functionality can be wrapped - // in a .NET class for easy consumption. The associated JavaScript module is - // loaded on demand when first needed. - // - // This class can be registered as scoped DI service and then injected into Blazor - // components for use. - - public class ArweaveService : IAsyncDisposable - { - private readonly Lazy> moduleTask; - private readonly Lazy> arweaveTask; - //private readonly Lazy> aoTask; - - public ArweaveService(IJSRuntime jsRuntime) - { - moduleTask = new(() => LoadScripts("./_content/ArweaveBlazor/arweaveJsInterop.js", jsRuntime).AsTask()); - arweaveTask = new(() => LoadScripts("https://unpkg.com/arweave/bundles/web.bundle.min.js", jsRuntime).AsTask()); - //aoTask = new(() => LoadScripts("https://www.unpkg.com/@permaweb/aoconnect@0.0.48/dist/browser.js", jsRuntime).AsTask()); - InitArweave(); - } - - private async ValueTask InitArweave() - { - var module = await moduleTask.Value; - - await module.InvokeVoidAsync("InitArweave"); - } - - public ValueTask LoadScripts(string url, IJSRuntime jsRuntime) - { - return jsRuntime.InvokeAsync("import", url); - } - - public async ValueTask HasArConnectAsync() - { - var module = await moduleTask.Value; - - var result = await module.InvokeAsync("HasArConnect"); - return result; - } - - public async ValueTask ConnectAsync(string[] permissions, string? appName = null, string? appLogo = null) - { - var module = await moduleTask.Value; - - try - { - var appInfo = new - { - name = appName, - logo = appLogo - }; - - await module.InvokeVoidAsync("Connect", permissions, appInfo); - } - catch (JSException jsex) - { } - } - - public async ValueTask DisconnectAsync() - { - var module = await moduleTask.Value; - - try - { - await module.InvokeVoidAsync("Disconnect"); - } - catch(JSException jsex) - { } - } - - public async ValueTask SendAsync(string processId, string? data, List? tags = null) - { - var module = await moduleTask.Value; - var result = await module.InvokeAsync("Send", processId, data, tags); - return result; - } - - public async ValueTask SendDryRunAsync(string processId, string? data, List? tags = null) - { - var module = await moduleTask.Value; - var result = await module.InvokeAsync("SendDryRun", processId, data, tags); - return result; - } - - - public async ValueTask GetResultAsync(string processId, string msgId) - { - var module = await moduleTask.Value; - - var result = await module.InvokeAsync("GetResult", processId, msgId); - return result; - } - - public async ValueTask GetResultsAsync(string processId, int limit) - { - var module = await moduleTask.Value; - - try - { - await module.InvokeVoidAsync("GetResults", processId, limit); - } - catch (JSException jsex) - { } - } - - public async ValueTask GetWalletBalanceAsync(string address) - { - var module = await moduleTask.Value; - var result = await module.InvokeAsync("GetWalletBalance", address); - return result; - } - - public async ValueTask GetActiveAddress() - { - var module = await moduleTask.Value; - var result = await module.InvokeAsync("GetActiveAddress"); - return result; - } - - public async ValueTask DisposeAsync() - { - if (moduleTask.IsValueCreated) - { - var module = await moduleTask.Value; - await module.DisposeAsync(); - } - } - - - - } -} \ No newline at end of file diff --git a/src/ArweaveBlazor/Models/BalanceResult.cs b/src/ArweaveBlazor/Models/BalanceResult.cs deleted file mode 100644 index 996ce60..0000000 --- a/src/ArweaveBlazor/Models/BalanceResult.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Text.Json.Serialization; - -namespace ArweaveBlazor.Models -{ - public class BalanceResult - { - [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)] - public long Balance { get; set; } = 0; - public string Owner { get; set; } = default!; - public string Symbol { get; set; } = default!; - - } -} diff --git a/src/ArweaveBlazor/Models/Tag.cs b/src/ArweaveBlazor/Models/Tag.cs deleted file mode 100644 index d1e7614..0000000 --- a/src/ArweaveBlazor/Models/Tag.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.Json.Serialization; -using System.Threading.Tasks; - -namespace ArweaveBlazor.Models -{ - public class Tag - { - [JsonPropertyName("name")] - public required string Name { get; set; } - - [JsonPropertyName("value")] - public required string Value { get; set; } - } -} diff --git a/src/ArweaveBlazor/ServiceCollectionExtensions.cs b/src/ArweaveBlazor/ServiceCollectionExtensions.cs deleted file mode 100644 index af0d2c8..0000000 --- a/src/ArweaveBlazor/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace ArweaveBlazor -{ - public static class ServiceCollectionExtensions - { - public static void AddArweaveBlazor(this IServiceCollection services) - { - services.AddScoped(); - } - } -} diff --git a/src/ArweaveBlazor/wwwroot/arweaveJsInterop.js b/src/ArweaveBlazor/wwwroot/arweaveJsInterop.js deleted file mode 100644 index 2b84c68..0000000 --- a/src/ArweaveBlazor/wwwroot/arweaveJsInterop.js +++ /dev/null @@ -1,148 +0,0 @@ -// This is a JavaScript module that is loaded on demand. It can export any number of -// functions, and may import other JavaScript modules if required. -import { - message, - result, - results, - dryrun, - createDataItemSigner -} from "https://www.unpkg.com/@permaweb/aoconnect@0.0.45/dist/browser.js"; - -let arweave; - -export function loadJs(sourceUrl) { - if (sourceUrl.Length == 0) { - console.error("Invalid source URL"); - return; - } - - var tag = document.createElement('script'); - tag.src = sourceUrl; - tag.type = "text/javascript"; - - //tag.onload = function () { - // console.log("Script loaded successfully"); - //} - - tag.onerror = function () { - console.error("Failed to load script"); - } - - document.body.appendChild(tag); -} - -export async function InitArweave() { - arweave = Arweave.init({}); -} - -export async function HasArConnect() { - if (window.arweaveWallet) { - return true; - } - else { - return false; - } -}; - -export async function GetWalletBalance(address) { - var result = await arweave.wallets.getBalance(address) - return result; -} - -export async function Connect(permissions, appInfo) { - var result = await window.arweaveWallet.connect(permissions, appInfo) - return result; -} - -export async function Disconnect() { - await window.arweaveWallet.disconnect() -} - -export async function GetActiveAddress(permissions, appInfo) { - - try { - var result = await window.arweaveWallet.getActiveAddress() - return result; - } - catch { } - return null; -} - -export async function Send(processId, data, tags) { - //let tags = [ - // { name: "Your-Tag-Name-Here", value: "your-tag-value" }, - // { name: "Another-Tag", value: "another-value" }, - //]; - let signer = createDataItemSigner(window.arweaveWallet); - - try { - let result = await message({ - process: processId, - tags: tags, - signer: signer, - data: data, - }); - - return result; - } catch (error) { - console.error(error); - } - -} - - -export async function SendDryRun(processId, data, tags) { - //let tags = [ - // { name: "Your-Tag-Name-Here", value: "your-tag-value" }, - // { name: "Another-Tag", value: "another-value" }, - //]; - //let signer = createDataItemSigner(window.arweaveWallet); - - try { - let { Messages, Spawns, Output, Error } = await dryrun({ - process: processId, - tags: tags, - //signer: signer, - data: data, - }); - - //console.log(Messages); - if (Messages.length > 0) { - return Messages[0].Data; - } - return null; - - } catch (error) { - console.error(error); - } - -} - - -export async function GetResult(processId, msgId) { - let { Messages, Spawns, Output, Error } = await result({ - // the arweave TXID of the message - message: msgId, - // the arweave TXID of the process - process: processId, - }); - - //console.log(Messages); - - if (Messages.length > 0) { - return Messages[0].Data; - } - return null; -} - -export async function GetResults(processId, limit) { - // fetching the first page of results - let resultsOut = await results({ - process: processId, - sort: "ASC", - limit: limit, - }); - - console.log(resultsOut); -} - diff --git a/src/aoWebWallet.sln b/src/aoWebWallet.sln index 71161e2..c0ab0cd 100644 --- a/src/aoWebWallet.sln +++ b/src/aoWebWallet.sln @@ -7,12 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "aoWebWallet", "aoWebWallet\ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libs", "Libs", "{06E5BC39-764A-48B9-B4F9-F48387A2C965}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ArweaveAO", "ArweaveAO\ArweaveAO.csproj", "{097DE302-25DA-4052-9983-6D856F9A00C6}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "webvNext.DataLoader", "webvNext.DataLoader\webvNext.DataLoader.csproj", "{17CA4374-64D0-4618-852F-8A76D0A57166}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ArweaveBlazor", "ArweaveBlazor\ArweaveBlazor.csproj", "{0420127C-D20C-44C8-B5E6-307313ACF10C}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -23,26 +19,16 @@ Global {DED1DD2B-BC48-47C3-8DAC-8E17EE796E2B}.Debug|Any CPU.Build.0 = Debug|Any CPU {DED1DD2B-BC48-47C3-8DAC-8E17EE796E2B}.Release|Any CPU.ActiveCfg = Release|Any CPU {DED1DD2B-BC48-47C3-8DAC-8E17EE796E2B}.Release|Any CPU.Build.0 = Release|Any CPU - {097DE302-25DA-4052-9983-6D856F9A00C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {097DE302-25DA-4052-9983-6D856F9A00C6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {097DE302-25DA-4052-9983-6D856F9A00C6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {097DE302-25DA-4052-9983-6D856F9A00C6}.Release|Any CPU.Build.0 = Release|Any CPU {17CA4374-64D0-4618-852F-8A76D0A57166}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {17CA4374-64D0-4618-852F-8A76D0A57166}.Debug|Any CPU.Build.0 = Debug|Any CPU {17CA4374-64D0-4618-852F-8A76D0A57166}.Release|Any CPU.ActiveCfg = Release|Any CPU {17CA4374-64D0-4618-852F-8A76D0A57166}.Release|Any CPU.Build.0 = Release|Any CPU - {0420127C-D20C-44C8-B5E6-307313ACF10C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0420127C-D20C-44C8-B5E6-307313ACF10C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0420127C-D20C-44C8-B5E6-307313ACF10C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0420127C-D20C-44C8-B5E6-307313ACF10C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {097DE302-25DA-4052-9983-6D856F9A00C6} = {06E5BC39-764A-48B9-B4F9-F48387A2C965} {17CA4374-64D0-4618-852F-8A76D0A57166} = {06E5BC39-764A-48B9-B4F9-F48387A2C965} - {0420127C-D20C-44C8-B5E6-307313ACF10C} = {06E5BC39-764A-48B9-B4F9-F48387A2C965} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {432E3F8E-53FF-4D9C-869D-48449BD3B8B4} diff --git a/src/aoWebWallet/Models/Wallet.cs b/src/aoWebWallet/Models/Wallet.cs index b0e1d44..5baff19 100644 --- a/src/aoWebWallet/Models/Wallet.cs +++ b/src/aoWebWallet/Models/Wallet.cs @@ -1,15 +1,46 @@ -namespace aoWebWallet.Models +using aoWebWallet.Pages; +using System.Reflection.Metadata.Ecma335; + +namespace aoWebWallet.Models { public class Wallet { public required string Address { get; set; } public string? Name { get; set; } + public string? Jwk { get; set; } public WalletTypes Source { get; set; } public bool IsConnected { get; set; } public bool IsReadOnly { get; set; } + public DateTimeOffset? LastBackedUpDate { get; set; } public DateTimeOffset AddedDate { get; set; } public DateTimeOffset LastUsedDate { get; set; } + + public bool NeedsBackup => Source == WalletTypes.Generated && !string.IsNullOrEmpty(Jwk) && !LastBackedUpDate.HasValue; + + public bool CanSend + { + get + { + if (IsReadOnly) + return false; + + var result = Source switch + { + WalletTypes.Manual => false, + WalletTypes.None => false, + WalletTypes.ArConnect => IsConnected, + WalletTypes.Explorer => false, + WalletTypes.Generated => !string.IsNullOrEmpty(Jwk), + WalletTypes.Imported => !string.IsNullOrEmpty(Jwk), + _ => false + }; + + return result; + + } + } + } public enum WalletTypes @@ -17,6 +48,8 @@ public enum WalletTypes None = 0, Manual, ArConnect, - Explorer + Explorer, + Generated, + Imported } } diff --git a/src/aoWebWallet/Pages/WalletDetail.razor b/src/aoWebWallet/Pages/WalletDetail.razor index 0185904..ca8e70c 100644 --- a/src/aoWebWallet/Pages/WalletDetail.razor +++ b/src/aoWebWallet/Pages/WalletDetail.razor @@ -108,7 +108,7 @@ - @if (!(BindingContext.SelectedWallet?.IsReadOnly ?? true) && (BindingContext.SelectedWallet?.IsConnected ?? false)) + @if ((BindingContext.SelectedWallet?.CanSend ?? false)) { var hasBalance = balance.Data?.BalanceData?.Balance ?? 0; diff --git a/src/aoWebWallet/Pages/Wallets.razor b/src/aoWebWallet/Pages/Wallets.razor index 2d1b0d4..1eacc98 100644 --- a/src/aoWebWallet/Pages/Wallets.razor +++ b/src/aoWebWallet/Pages/Wallets.razor @@ -60,10 +60,19 @@ { } + @if (wallet.NeedsBackup) + { + + Wallet not backed up yet! + } + @if(!string.IsNullOrEmpty(wallet.Jwk)) + { + + } @@ -79,6 +88,8 @@ + + @@ -113,4 +124,10 @@ } StateHasChanged(); } + + private async void DownloadWallet(Wallet wallet) + { + await BindingContext.DownloadWallet(wallet); + StateHasChanged(); + } } diff --git a/src/aoWebWallet/Shared/AddArConnectComponent.razor b/src/aoWebWallet/Shared/AddArConnectComponent.razor index 71d9abb..8a5bf8a 100644 --- a/src/aoWebWallet/Shared/AddArConnectComponent.razor +++ b/src/aoWebWallet/Shared/AddArConnectComponent.razor @@ -106,7 +106,7 @@ { Snackbar.Add($"Please allow this website access to ArConnect", Severity.Info); } - await ArweaveService.ConnectAsync(new string[] { "ACCESS_ADDRESS", "SIGN_TRANSACTION" }, "aoWebWallet"); + await ArweaveService.ConnectArConnectAsync(new string[] { "ACCESS_ADDRESS", "SIGN_TRANSACTION" }, "aoWebWallet"); await BindingContext.GetActiveArConnectAddress(); diff --git a/src/aoWebWallet/Shared/AddGenerateWalletComponent.razor b/src/aoWebWallet/Shared/AddGenerateWalletComponent.razor new file mode 100644 index 0000000..9a8f975 --- /dev/null +++ b/src/aoWebWallet/Shared/AddGenerateWalletComponent.razor @@ -0,0 +1,67 @@ +@using aoWebWallet.Models +@inherits MvvmComponentBase +@inject TokenClient TokenClient +@inject ArweaveService ArweaveService +@inject ISnackbar Snackbar + + + + @(IsExpanded ? "Generate new wallet" : "Generate new wallet") + + + + @Progress +
+ Generate +
+
+
+
+ + + +@code { + [Parameter] + public bool HideAddButton { get; set; } + + [CascadingParameter] MudDialogInstance? MudDialog { get; set; } = default!; + + + public string? Name { get; set; } + public string? Progress { get; set; } + + [Parameter] + public bool IsExpanded { get; set; } + + private void OnExpandCollapseClick() + { + IsExpanded = !IsExpanded; + } + + public async Task Submit() + { + var jwk = await ArweaveService.GenerateWallet(); + var address = await ArweaveService.GetAddress(jwk); + + var wallet = new Wallet + { + Address = address, + Name = Name, + Jwk = jwk, + Source = WalletTypes.Generated, + IsReadOnly = false, + LastBackedUpDate = null, + AddedDate = DateTimeOffset.UtcNow + }; + + await BindingContext.SaveWallet(wallet); + + Snackbar.Add($"Wallet added ({address})", Severity.Info); + + if (MudDialog != null) + { + MudDialog.Close(); + } + return true; + } +} diff --git a/src/aoWebWallet/Shared/AddUploadWalletComponent.razor b/src/aoWebWallet/Shared/AddUploadWalletComponent.razor new file mode 100644 index 0000000..22d8e04 --- /dev/null +++ b/src/aoWebWallet/Shared/AddUploadWalletComponent.razor @@ -0,0 +1,156 @@ +@using aoWebWallet.Models +@inherits MvvmComponentBase +@inject TokenClient TokenClient +@inject ArweaveService ArweaveService +@inject ISnackbar Snackbar + + + + @(IsExpanded ? "Load .json wallet" : "Load .json wallet") + + + + + + + + + + + + + +@code { + [Parameter] + public bool HideAddButton { get; set; } + + [CascadingParameter] MudDialogInstance? MudDialog { get; set; } = default!; + + + public string? Progress { get; set; } + + [Parameter] + public bool IsExpanded { get; set; } + + private void OnExpandCollapseClick() + { + IsExpanded = !IsExpanded; + } + + private const string DefaultDragClass = "relative rounded-lg border-2 border-dashed pa-4 mt-4 mud-width-full mud-height-full z-10"; + private string _dragClass = DefaultDragClass; + private readonly List _fileNames = new(); + + private async Task Clear() + { + _fileNames.Clear(); + ClearDragClass(); + await Task.Delay(100); + } + + private async Task OnInputFileChanged(InputFileChangeEventArgs e) + { + ClearDragClass(); + var files = e.GetMultipleFiles(); + foreach (var file in files) + { + // Ensure file is not null and has content + if (file != null && file.Size > 0) + { + using (var memoryStream = new MemoryStream()) + { + await file.OpenReadStream().CopyToAsync(memoryStream); + memoryStream.Seek(0, SeekOrigin.Begin); + + using (var reader = new StreamReader(memoryStream)) + { + try + { + var jwk = await reader.ReadToEndAsync(); + var address = await ArweaveService.GetAddress(jwk); + var name = file.Name; + + var wallet = new Wallet + { + Address = address, + Name = name, + Jwk = jwk, + Source = WalletTypes.Imported, + IsReadOnly = false, + AddedDate = DateTimeOffset.UtcNow + }; + + _fileNames.Add(wallet); + } + catch { } + + } + } + } + } + } + + private async Task Upload() + { + foreach (var wallet in _fileNames) + { + await BindingContext.SaveWallet(wallet); + + Snackbar.Add($"Wallet added ({wallet.Address})", Severity.Info); + } + + if (MudDialog != null) + { + MudDialog.Close(); + } + } + + private void SetDragClass() + => _dragClass = $"{DefaultDragClass} mud-border-primary"; + + private void ClearDragClass() + => _dragClass = DefaultDragClass; +} diff --git a/src/aoWebWallet/Shared/AddWalletDialog.razor b/src/aoWebWallet/Shared/AddWalletDialog.razor index 297486f..47e4575 100644 --- a/src/aoWebWallet/Shared/AddWalletDialog.razor +++ b/src/aoWebWallet/Shared/AddWalletDialog.razor @@ -7,6 +7,8 @@ + + diff --git a/src/aoWebWallet/Shared/SendTokenDialog.razor b/src/aoWebWallet/Shared/SendTokenDialog.razor index 37238a7..49bab38 100644 --- a/src/aoWebWallet/Shared/SendTokenDialog.razor +++ b/src/aoWebWallet/Shared/SendTokenDialog.razor @@ -134,6 +134,12 @@ { if (string.IsNullOrEmpty(Address)) return; + if (Address.Length != 43) + { + Progress = "Address length must be 43 characters."; + StateHasChanged(); + return; + } if (string.IsNullOrEmpty(BindingContext.SelectedBalanceDataVM?.BalanceData?.TokenId) || BindingContext.SelectedBalanceDataVM.Token?.TokenData?.Denomination == null @@ -145,8 +151,13 @@ this.StateHasChanged(); + if (BindingContext.SelectedWallet == null) + { + throw new Exception("SelectedWallet is null"); + } + long amountLong = BalanceHelper.DecimalToTokenAmount(Amount, BindingContext.SelectedBalanceDataVM.Token.TokenData.Denomination!.Value); - var result = await BindingContext.SendTokenWithArConnect(BindingContext.SelectedBalanceDataVM.Token.TokenId, Address, amountLong); + var result = await BindingContext.SendToken(BindingContext.SelectedWallet, BindingContext.SelectedBalanceDataVM.Token.TokenId, Address, amountLong); TransactionId = result?.Id; if (!string.IsNullOrEmpty(BindingContext.SelectedAddress)) diff --git a/src/aoWebWallet/ViewModels/MainViewModel.cs b/src/aoWebWallet/ViewModels/MainViewModel.cs index 77b0388..b427782 100644 --- a/src/aoWebWallet/ViewModels/MainViewModel.cs +++ b/src/aoWebWallet/ViewModels/MainViewModel.cs @@ -258,6 +258,22 @@ public async Task DeleteWallet(Wallet wallet) await LoadWalletList(); } + public async Task DownloadWallet(Wallet wallet) + { + if (string.IsNullOrEmpty(wallet.Jwk)) + return; + + var address = await arweaveService.GetAddress(wallet.Jwk); + var result = await arweaveService.SaveFile($"{address}.json", wallet.Jwk); + wallet.LastBackedUpDate = DateTimeOffset.UtcNow; + + if (this.WalletList.Data != null) + { + await storageService.SaveWalletList(this.WalletList.Data); + //await LoadWalletList(); + } + } + public async Task ClearUserData() { memoryDataCache.Clear(); @@ -522,6 +538,32 @@ public async Task GetActiveArConnectAddress() } } + public Task SendToken(Wallet wallet, string tokenId, string address, long amount) + { + if (wallet.Source == WalletTypes.ArConnect) + return SendTokenWithArConnect(tokenId, address, amount); + + if (!string.IsNullOrEmpty(wallet.Jwk)) + return SendTokenWithJwk(wallet.Jwk, tokenId, address, amount); + + return Task.FromResult(default); + + } + + public Task SendTokenWithJwk(string jwk, string tokenId, string address, long amount) + => LastTransactionId.DataLoader.LoadAsync(async () => + { + var idResult = await arweaveService.SendAsync(jwk, tokenId, null, new List + { + new ArweaveBlazor.Models.Tag() { Name = "Action", Value = "Transfer"}, + new ArweaveBlazor.Models.Tag() { Name = "Wallet", Value = "aoww"}, + new ArweaveBlazor.Models.Tag() { Name = "Recipient", Value = address}, + new ArweaveBlazor.Models.Tag() { Name = "Quantity", Value = amount.ToString()}, + }); + + return new Transaction { Id = idResult }; + }); + public Task SendTokenWithArConnect(string tokenId, string address, long amount) => LastTransactionId.DataLoader.LoadAsync(async () => { @@ -529,7 +571,7 @@ public async Task GetActiveArConnectAddress() if (string.IsNullOrEmpty(ActiveArConnectAddress)) return null; - var idResult = await arweaveService.SendAsync(tokenId, null, new List + var idResult = await arweaveService.SendAsync(null, tokenId, null, new List { new ArweaveBlazor.Models.Tag() { Name = "Action", Value = "Transfer"}, new ArweaveBlazor.Models.Tag() { Name = "Wallet", Value = "aoww"}, @@ -547,7 +589,7 @@ public async Task GetActiveArConnectAddress() if (string.IsNullOrEmpty(ActiveArConnectAddress)) return null; - var idResult = await arweaveService.SendAsync(CLAIM_PROCESS_ID, null, new List + var idResult = await arweaveService.SendAsync(null, CLAIM_PROCESS_ID, null, new List { new ArweaveBlazor.Models.Tag() { Name = "Action", Value = "claim" + claim}, new ArweaveBlazor.Models.Tag() { Name = "Wallet", Value = "aoww"}, diff --git a/src/aoWebWallet/aoWebWallet.csproj b/src/aoWebWallet/aoWebWallet.csproj index 9f290f2..beadf3d 100644 --- a/src/aoWebWallet/aoWebWallet.csproj +++ b/src/aoWebWallet/aoWebWallet.csproj @@ -12,7 +12,9 @@ - + + + @@ -21,8 +23,6 @@ - -