diff --git a/AElf.Client.sln b/AElf.Client.sln
new file mode 100644
index 0000000..ce42ea6
--- /dev/null
+++ b/AElf.Client.sln
@@ -0,0 +1,37 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{940361AC-2167-4D30-A4F6-9A543C608196}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{7CD2B508-C765-4720-B430-94E79135797A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client", "src\AElf.Client\AElf.Client.csproj", "{1AE7844D-B4D9-4F5A-9D25-7E551B61138E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client.Test", "test\AElf.Client.Test\AElf.Client.Test.csproj", "{4D019C99-8B1C-42B0-8630-F1E3661F414B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client.Protobuf", "src\AElf.Client.Protobuf\AElf.Client.Protobuf.csproj", "{01B13EE5-9892-4D2A-8E77-C0A4A9575753}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {1AE7844D-B4D9-4F5A-9D25-7E551B61138E} = {940361AC-2167-4D30-A4F6-9A543C608196}
+ {4D019C99-8B1C-42B0-8630-F1E3661F414B} = {7CD2B508-C765-4720-B430-94E79135797A}
+ {01B13EE5-9892-4D2A-8E77-C0A4A9575753} = {940361AC-2167-4D30-A4F6-9A543C608196}
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1AE7844D-B4D9-4F5A-9D25-7E551B61138E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1AE7844D-B4D9-4F5A-9D25-7E551B61138E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1AE7844D-B4D9-4F5A-9D25-7E551B61138E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1AE7844D-B4D9-4F5A-9D25-7E551B61138E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4D019C99-8B1C-42B0-8630-F1E3661F414B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4D019C99-8B1C-42B0-8630-F1E3661F414B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4D019C99-8B1C-42B0-8630-F1E3661F414B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4D019C99-8B1C-42B0-8630-F1E3661F414B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {01B13EE5-9892-4D2A-8E77-C0A4A9575753}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {01B13EE5-9892-4D2A-8E77-C0A4A9575753}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {01B13EE5-9892-4D2A-8E77-C0A4A9575753}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {01B13EE5-9892-4D2A-8E77-C0A4A9575753}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/all.sln b/all.sln
index 3e3a5d1..9de7f43 100644
--- a/all.sln
+++ b/all.sln
@@ -10,15 +10,23 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client", "src\AElf.Cli
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client.Protobuf", "src\AElf.Client.Protobuf\AElf.Client.Protobuf.csproj", "{E7DF7523-2FB5-45B3-9EAA-9B759FDDC2EB}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TokenManager", "examples\TokenManager\TokenManager.csproj", "{CA0B4594-2549-4DB1-9079-EA5FD739C6B6}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ElectionViewer", "examples\ElectionViewer\ElectionViewer.csproj", "{E678AABE-AF7B-45F4-B931-CF0D77C5AECA}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AEDPoSViewer", "examples\AEDPoSViewer\AEDPoSViewer.csproj", "{BE0E29FA-A9C6-4E03-9E0C-297CCF7C5729}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client.Test", "test\AElf.Client.Test\AElf.Client.Test.csproj", "{4D019C99-8B1C-42B0-8630-F1E3661F414B}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client.Abp", "src\AElf.Client.Abp\AElf.Client.Abp.csproj", "{BBE11EF4-5CD6-4918-8E6C-74BF61C1A87F}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client.Core", "src\AElf.Client.Core\AElf.Client.Core.csproj", "{BBE11EF4-5CD6-4918-8E6C-74BF61C1A87F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client.TestBase", "test\AElf.Client.TestBase\AElf.Client.TestBase.csproj", "{D542FBDB-DFE1-46C2-8C4E-9A5643F3C401}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client.Genesis", "examples\AElf.Client.Genesis\AElf.Client.Genesis.csproj", "{A6F6AF4C-A783-4EC3-A03F-F1576020BC49}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client.Consensus.AEDPoS", "examples\AElf.Client.Consensus.AEDPoS\AElf.Client.Consensus.AEDPoS.csproj", "{46531278-7E47-4D6F-AD45-A6870E624105}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client.Parliament", "examples\AElf.Client.Parliament\AElf.Client.Parliament.csproj", "{12B17C25-1A00-4BB7-9911-9AC06988C261}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client.Token", "examples\AElf.Client.Token\AElf.Client.Token.csproj", "{0FD6224B-4C4B-49C3-BC25-5C0B1FDBB077}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AElf.Client.CrossChain", "examples\AElf.Client.CrossChain\AElf.Client.CrossChain.csproj", "{0657BEEB-97B1-4250-9252-6685A99B5D10}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -28,11 +36,15 @@ Global
GlobalSection(NestedProjects) = preSolution
{1AE7844D-B4D9-4F5A-9D25-7E551B61138E} = {940361AC-2167-4D30-A4F6-9A543C608196}
{E7DF7523-2FB5-45B3-9EAA-9B759FDDC2EB} = {940361AC-2167-4D30-A4F6-9A543C608196}
- {CA0B4594-2549-4DB1-9079-EA5FD739C6B6} = {5D1BDC45-D6F1-4359-868B-CB85CEC4ABD8}
- {E678AABE-AF7B-45F4-B931-CF0D77C5AECA} = {5D1BDC45-D6F1-4359-868B-CB85CEC4ABD8}
{BE0E29FA-A9C6-4E03-9E0C-297CCF7C5729} = {5D1BDC45-D6F1-4359-868B-CB85CEC4ABD8}
{4D019C99-8B1C-42B0-8630-F1E3661F414B} = {7CD2B508-C765-4720-B430-94E79135797A}
{BBE11EF4-5CD6-4918-8E6C-74BF61C1A87F} = {940361AC-2167-4D30-A4F6-9A543C608196}
+ {D542FBDB-DFE1-46C2-8C4E-9A5643F3C401} = {7CD2B508-C765-4720-B430-94E79135797A}
+ {A6F6AF4C-A783-4EC3-A03F-F1576020BC49} = {5D1BDC45-D6F1-4359-868B-CB85CEC4ABD8}
+ {46531278-7E47-4D6F-AD45-A6870E624105} = {5D1BDC45-D6F1-4359-868B-CB85CEC4ABD8}
+ {12B17C25-1A00-4BB7-9911-9AC06988C261} = {5D1BDC45-D6F1-4359-868B-CB85CEC4ABD8}
+ {0FD6224B-4C4B-49C3-BC25-5C0B1FDBB077} = {5D1BDC45-D6F1-4359-868B-CB85CEC4ABD8}
+ {0657BEEB-97B1-4250-9252-6685A99B5D10} = {5D1BDC45-D6F1-4359-868B-CB85CEC4ABD8}
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1AE7844D-B4D9-4F5A-9D25-7E551B61138E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@@ -43,14 +55,6 @@ Global
{E7DF7523-2FB5-45B3-9EAA-9B759FDDC2EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E7DF7523-2FB5-45B3-9EAA-9B759FDDC2EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E7DF7523-2FB5-45B3-9EAA-9B759FDDC2EB}.Release|Any CPU.Build.0 = Release|Any CPU
- {CA0B4594-2549-4DB1-9079-EA5FD739C6B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {CA0B4594-2549-4DB1-9079-EA5FD739C6B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {CA0B4594-2549-4DB1-9079-EA5FD739C6B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {CA0B4594-2549-4DB1-9079-EA5FD739C6B6}.Release|Any CPU.Build.0 = Release|Any CPU
- {E678AABE-AF7B-45F4-B931-CF0D77C5AECA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {E678AABE-AF7B-45F4-B931-CF0D77C5AECA}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {E678AABE-AF7B-45F4-B931-CF0D77C5AECA}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {E678AABE-AF7B-45F4-B931-CF0D77C5AECA}.Release|Any CPU.Build.0 = Release|Any CPU
{BE0E29FA-A9C6-4E03-9E0C-297CCF7C5729}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BE0E29FA-A9C6-4E03-9E0C-297CCF7C5729}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BE0E29FA-A9C6-4E03-9E0C-297CCF7C5729}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -63,5 +67,29 @@ Global
{BBE11EF4-5CD6-4918-8E6C-74BF61C1A87F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BBE11EF4-5CD6-4918-8E6C-74BF61C1A87F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BBE11EF4-5CD6-4918-8E6C-74BF61C1A87F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D542FBDB-DFE1-46C2-8C4E-9A5643F3C401}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D542FBDB-DFE1-46C2-8C4E-9A5643F3C401}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D542FBDB-DFE1-46C2-8C4E-9A5643F3C401}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D542FBDB-DFE1-46C2-8C4E-9A5643F3C401}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A6F6AF4C-A783-4EC3-A03F-F1576020BC49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A6F6AF4C-A783-4EC3-A03F-F1576020BC49}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A6F6AF4C-A783-4EC3-A03F-F1576020BC49}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A6F6AF4C-A783-4EC3-A03F-F1576020BC49}.Release|Any CPU.Build.0 = Release|Any CPU
+ {46531278-7E47-4D6F-AD45-A6870E624105}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {46531278-7E47-4D6F-AD45-A6870E624105}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {46531278-7E47-4D6F-AD45-A6870E624105}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {46531278-7E47-4D6F-AD45-A6870E624105}.Release|Any CPU.Build.0 = Release|Any CPU
+ {12B17C25-1A00-4BB7-9911-9AC06988C261}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {12B17C25-1A00-4BB7-9911-9AC06988C261}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {12B17C25-1A00-4BB7-9911-9AC06988C261}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {12B17C25-1A00-4BB7-9911-9AC06988C261}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0FD6224B-4C4B-49C3-BC25-5C0B1FDBB077}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0FD6224B-4C4B-49C3-BC25-5C0B1FDBB077}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0FD6224B-4C4B-49C3-BC25-5C0B1FDBB077}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0FD6224B-4C4B-49C3-BC25-5C0B1FDBB077}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0657BEEB-97B1-4250-9252-6685A99B5D10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0657BEEB-97B1-4250-9252-6685A99B5D10}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0657BEEB-97B1-4250-9252-6685A99B5D10}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0657BEEB-97B1-4250-9252-6685A99B5D10}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 464e1d0..3f22733 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -9,7 +9,7 @@ jobs:
- task: UseDotNet@2
displayName: 'Install .NET Core SDK'
inputs:
- version: 3.1.101
+ version: 6.0.300
- powershell: ./scripts/aelf-node/start-window.ps1
displayName: 'Build and Test'
# All tasks on Linux
@@ -25,7 +25,7 @@ jobs:
steps:
- task: DotNetCoreInstaller@0
inputs:
- version: '3.1.101'
+ version: '6.0.300'
- script: cd scripts/aelf-node && bash start.sh
displayName: 'Deploy a full node'
- script: bash build.sh -target=test
@@ -40,7 +40,7 @@ jobs:
steps:
- task: DotNetCoreInstaller@0
inputs:
- version: '3.1.101'
+ version: '6.0.300'
- script: cd scripts/aelf-node && bash start-mac.sh
displayName: 'Deploy a full node'
- script: bash build.sh -target=test
diff --git a/build.config b/build.config
index 803c029..015ef8e 100644
--- a/build.config
+++ b/build.config
@@ -1,3 +1,3 @@
#!/usr/bin/env bash
CAKE_VERSION=0.37.0
-DOTNET_VERSION=3.1.101
+DOTNET_VERSION=6.0.300
diff --git a/examples/AEDPoSViewer/AEDPoSViewer.csproj b/examples/AEDPoSViewer/AEDPoSViewer.csproj
index a356a80..005dac9 100644
--- a/examples/AEDPoSViewer/AEDPoSViewer.csproj
+++ b/examples/AEDPoSViewer/AEDPoSViewer.csproj
@@ -8,7 +8,7 @@
-
+
@@ -18,6 +18,7 @@
+
diff --git a/examples/AEDPoSViewer/AEDPoSViewerHostedService.cs b/examples/AEDPoSViewer/AEDPoSViewerHostedService.cs
index bdb0b9c..c1f2491 100644
--- a/examples/AEDPoSViewer/AEDPoSViewerHostedService.cs
+++ b/examples/AEDPoSViewer/AEDPoSViewerHostedService.cs
@@ -1,5 +1,3 @@
-using System.Threading;
-using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
@@ -34,8 +32,8 @@ public async Task StartAsync(CancellationToken cancellationToken)
await _abpApplication.InitializeAsync();
- var helloWorldService = _abpApplication.ServiceProvider.GetRequiredService();
- await helloWorldService.RunAsync();
+ var viewerService = _abpApplication.ServiceProvider.GetRequiredService();
+ await viewerService.RunAsync();
}
public async Task StopAsync(CancellationToken cancellationToken)
diff --git a/examples/AEDPoSViewer/AEDPoSViewerModule.cs b/examples/AEDPoSViewer/AEDPoSViewerModule.cs
index 1bd743a..48c582d 100644
--- a/examples/AEDPoSViewer/AEDPoSViewerModule.cs
+++ b/examples/AEDPoSViewer/AEDPoSViewerModule.cs
@@ -1,4 +1,4 @@
-using AElf.Client.Abp;
+using AElf.Client.Core;
using Volo.Abp.Modularity;
namespace AEDPoSViewer;
@@ -8,5 +8,8 @@ namespace AEDPoSViewer;
)]
public class AEDPoSViewerModule : AbpModule
{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ }
}
\ No newline at end of file
diff --git a/examples/AEDPoSViewer/AEDPoSViewerService.cs b/examples/AEDPoSViewer/AEDPoSViewerService.cs
index 6dafa91..68e2deb 100644
--- a/examples/AEDPoSViewer/AEDPoSViewerService.cs
+++ b/examples/AEDPoSViewer/AEDPoSViewerService.cs
@@ -1,10 +1,13 @@
-using AElf.Client;
+using AEDPoSViewer.Data;
+using AElf;
+using AElf.Client.Core;
+using AElf.Client.Core.Options;
using AElf.Contracts.Consensus.AEDPoS;
-using Google.Protobuf;
+using AElf.Types;
using Google.Protobuf.WellKnownTypes;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.Options;
+using Spectre.Console;
using Volo.Abp.DependencyInjection;
namespace AEDPoSViewer;
@@ -13,26 +16,74 @@ public class AEDPoSViewerService : ITransientDependency
{
private IServiceScopeFactory ServiceScopeFactory { get; }
- public ILogger Logger { get; set; }
-
public AEDPoSViewerService(IServiceScopeFactory serviceScopeFactory)
{
ServiceScopeFactory = serviceScopeFactory;
-
- Logger = NullLogger.Instance;
}
public async Task RunAsync()
+ {
+ var currentRound = await GetCurrentRoundAsync();
+ for (var i = currentRound.RoundNumber - 4; i < currentRound.RoundNumber; i++)
+ {
+ DisplayRound(await GetRoundAsync(i));
+ }
+
+ DisplayRound(currentRound);
+ }
+
+ private async Task GetRoundAsync(long roundNumber)
{
using var scope = ServiceScopeFactory.CreateScope();
+ var clientConfig = scope.ServiceProvider.GetRequiredService>();
+
var clientService = scope.ServiceProvider.GetRequiredService();
- var result = await clientService.ViewSystemAsync(AEDPoSViewerConstants.ConsensusSmartContractName,
- "GetCurrentRoundInformation", new Empty(), EndpointType.MainNetSidechain.ToString(), "Ean");
+ return await clientService.ViewSystemAsync(AEDPoSViewerConstants.ConsensusSmartContractName,
+ "GetRoundInformation", new Int64Value { Value = roundNumber }, clientConfig.Value.ClientAlias);
+ }
+
+ private async Task GetCurrentRoundAsync()
+ {
+ using var scope = ServiceScopeFactory.CreateScope();
+
+ var clientConfig = scope.ServiceProvider.GetRequiredService>();
+
+ var clientService = scope.ServiceProvider.GetRequiredService();
+
+ return await clientService.ViewSystemAsync(AEDPoSViewerConstants.ConsensusSmartContractName,
+ "GetCurrentRoundInformation", new Empty(), clientConfig.Value.ClientAlias);
+ }
+
+ private void DisplayRound(Round round)
+ {
+ //AnsiConsole.MarkupLine($"[blue]Term:[/]\t{round.TermNumber}");
+ AnsiConsole.MarkupLine($"[blue]Round:[/]\t{round.RoundNumber}");
+ //AnsiConsole.MarkupLine($"[blue]Days:[/]\t{new TimeSpan(0, 0, 0, (int)round.BlockchainAge).TotalDays}");
+
+ var table = new Table();
+ table.AddColumn(new TableColumn(new Markup("[blue]Pubkey[/]")));
+ table.AddColumn(new TableColumn("[blue]Address[/]"));
+ table.AddColumn(new TableColumn("[blue]Order[/]"));
+ table.AddColumn(new TableColumn("[blue]Produced[/]"));
+ table.AddColumn(new TableColumn("[blue]Missed Slots[/]"));
+ foreach (var info in round.RealTimeMinersInformation.OrderBy(i => i.Value.Order))
+ {
+ var pubkey = info.Key;
+ var minerInRound = info.Value;
+ var address = Address.FromPublicKey(ByteArrayHelper.HexStringToByteArray(pubkey)).ToBase58();
+ BlockProducer.Map.TryGetValue(pubkey, out var displayPubkey);
+ var actualMiningTimes = minerInRound.ActualMiningTimes.Count;
+ var isAlarm = actualMiningTimes == 0;
+ table.AddRow(
+ (isAlarm ? "[red]" : "") + (displayPubkey ?? pubkey[..10]) + (isAlarm ? "[/]" : ""),
+ address,
+ minerInRound.Order.ToString(),
+ (isAlarm ? "[red]" : "") + actualMiningTimes + (isAlarm ? "[/]" : ""),
+ minerInRound.MissedTimeSlots.ToString());
+ }
- var round = new Round();
- round.MergeFrom(result);
- Logger.LogInformation($"Current round: {round}");
+ AnsiConsole.Write(table);
}
}
\ No newline at end of file
diff --git a/examples/AEDPoSViewer/Data/BlockProducerMap.cs b/examples/AEDPoSViewer/Data/BlockProducerMap.cs
new file mode 100644
index 0000000..dcd134e
--- /dev/null
+++ b/examples/AEDPoSViewer/Data/BlockProducerMap.cs
@@ -0,0 +1,47 @@
+namespace AEDPoSViewer.Data;
+
+public static class BlockProducer
+{
+ public static Dictionary Map;
+
+ static BlockProducer()
+ {
+ Map = new Dictionary
+ {
+ ["048a8e7562f14207a5e9cc41163a8b947cf826bd1628fa79b4e5345e014bd3cb139617ccbb1fed60a4cdd691a238f9d30f30bf50452d5a4d9b050de73d16ccd606"] =
+ "FBG",
+ ["04f34af28e68d7c9bcfc7a9797a4d894ee9a9d3d142e275cd254b6495ed7ec95f95411c9819950c23c36fd00a2c610947487bd6e0b3e3ed8d2c90f089fa4f0c02a"] =
+ "RockX",
+ ["04d92f55aa3ea457c24836b263aca894b7aa890eb17176b8d46b17d35d5a417e491a024c8974c1bfc7b586c15f329e5d7e707f888841ba984f32dec7631efd891a"] =
+ "CoinHuntingCommunity",
+ ["04cfe24816b93a4936d564c63fd7cdcc3e77c8f26037dec96b8ab5f209b161c6567df2a317d1bb5b5494eac41d8c457ac6b8242dff9af0147beabe0ecb28ea2b79"] =
+ "LumosSocial",
+ ["0454c2e605e790e8c6e295604eeb6e169af97e25862882f44cbff19502096e29460b425e7cb50da1215b5931057fa84dd812a66a15ead46a66a9972d3e3c3fe38b"] =
+ "bountyblok",
+ ["0476d07226df54bc3f0cbbf6ab86f5c9d2324860e9e3c36db2886555d7832eed89214f73dfe8c43e7efdd7157dfbb148966944fbcb1ad0bf812b6d3350858e9104"] =
+ "ChainExplorers",
+ ["04a45c95d121c659d9f90ce7c43236f0204b87e5d180a700d6a040f2ad60a4b7cb7f22aed7e2ed7205376edcabfd2d1efb011e46e45ec94eed23cad48b794ce89e"] =
+ "marbleGameFI",
+ ["040bcbc49d65a89e49dc7152b2720f5769e6132a2c2d8742d0b7d6efb7bc1a977355f5dbd05f565e3c8848cbce8c8a0250a8a2296dc74b3d4fa0335637de5b1ec7"] =
+ "Genesis5",
+ ["04c7132a91d3b3924d1afcf99b255dde5fc0fbb437e8cb3b0d3858e9bbbf7f30e2e39e3819ebb9f034963b6a7ed3e3c12e8528cfce6210f39cf12803f89877a890"] =
+ "OKX",
+ ["042f7cab8272e1f4e90e59e91bbe2c211f1a0e15a5b670aff517a02f625d678607a96723b6ce3232fcf6ad0fc988e3e198cdedebcc10cd4d86b4dddfd8a99edcf0"] =
+ "aelfin",
+ ["04f7760c46da886f7e06e8e665cbab7d63cfe825c680dce990fcb2c3b7a01c7236e0ae40aacb32bbc4fffc57ae45bc1fe5344461efeed2b4660aef3ec3f9e35b15"] =
+ "HuobiPool",
+ ["0458ad2ec4d8944bff7f3ab7b56a90ffca784b0632bdf8c4a952da153b24b3fbbda5432f5ef293ab7ced791969f5fe02b0b5e6bc5af7ce074a9dc386c8dab0e6db"] =
+ "MetaDefy",
+ ["04e6b61a5904cfa1e242051bd71a6adba572eaf325213f41a0ae4d0139fe63627d130e6e525c3d23732ae64f3bfc8959ca4174f6aef8ea7901b4c436f5cfc81371"] =
+ "Genesis2",
+ ["04ace35149bf24792b0a4c9ea327ef44061e4a6dffa598a24be054b8068d173e0c59f4a070417b7f544057c447f27678d6aa6b531b14ee996af9728ff2fabe7f42"] =
+ "Genesis3",
+ ["04dfc5398e6c0485cb4ee98f6202f81fd49c971fa21ef9f62e309a4b983cffae9149c13cf9a8d00c10153f45855943e1ec5ca399b7143cf336cc901c457e905236"] =
+ "Genesis1",
+ ["0485bc2868f15dc6ff07ec85e3ee6f5900bb3bf3c6c50c3f40d377a203c476fdade815ab5bba1ade2eefb20de26085ab1ab84317ba07b093aa622a536f32d35682"] =
+ "CoinMultiDex",
+ ["04c1b4a75fd9ba37e0a84b9916e517e9c591c5b9efacabf1feb1a3d34f38920a250454dc9dce0f811956d210804c904959be96a75a9d9b1410aa25f7d9e1b6f69c"] =
+ "Genesis4",
+ };
+ }
+}
\ No newline at end of file
diff --git a/examples/AEDPoSViewer/appsettings.json b/examples/AEDPoSViewer/appsettings.json
index ec1136b..f0b02d7 100644
--- a/examples/AEDPoSViewer/appsettings.json
+++ b/examples/AEDPoSViewer/appsettings.json
@@ -17,7 +17,7 @@
}
]
},
- "AElfAccount":{
+ "AElfAccount": {
"KeyDirectory": "",
"AccountConfigList": [
{
@@ -36,5 +36,10 @@
"PrivateKey": "5e2f12d13e4527ad1128e07db00f1614ec6b8b51662e68d4fdb42125ab384195",
}
]
+ },
+ "AElfClientConfig": {
+ "ClientAlias": "MainNetMainChain",
+ "AccountAlias": "Ean",
+ "CamelCase": false
}
}
\ No newline at end of file
diff --git a/examples/TokenManager/TokenManager.csproj b/examples/AElf.Client.Consensus.AEDPoS/AElf.Client.Consensus.AEDPoS.csproj
similarity index 50%
rename from examples/TokenManager/TokenManager.csproj
rename to examples/AElf.Client.Consensus.AEDPoS/AElf.Client.Consensus.AEDPoS.csproj
index b9de063..b1de127 100644
--- a/examples/TokenManager/TokenManager.csproj
+++ b/examples/AElf.Client.Consensus.AEDPoS/AElf.Client.Consensus.AEDPoS.csproj
@@ -1,10 +1,17 @@
- Exe
net6.0
enable
enable
+
+
+
+
+
+
+
+
diff --git a/examples/AElf.Client.Consensus.AEDPoS/AElfClientAEDPoSModule.cs b/examples/AElf.Client.Consensus.AEDPoS/AElfClientAEDPoSModule.cs
new file mode 100644
index 0000000..63f4b0f
--- /dev/null
+++ b/examples/AElf.Client.Consensus.AEDPoS/AElfClientAEDPoSModule.cs
@@ -0,0 +1,12 @@
+using AElf.Client.Core;
+using Volo.Abp.Modularity;
+
+namespace AElf.Client.Consensus.AEDPoS;
+
+[DependsOn(
+ typeof(AElfClientModule),
+ typeof(CoreAElfModule)
+)]
+public class AElfClientAEDPoSModule : AbpModule
+{
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Consensus.AEDPoS/AElfConsensusConstants.cs b/examples/AElf.Client.Consensus.AEDPoS/AElfConsensusConstants.cs
new file mode 100644
index 0000000..fcc333a
--- /dev/null
+++ b/examples/AElf.Client.Consensus.AEDPoS/AElfConsensusConstants.cs
@@ -0,0 +1,6 @@
+namespace AElf.Client.Consensus.AEDPoS;
+
+public class AElfConsensusConstants
+{
+ public const string ConsensusSmartContractName = "AElf.ContractNames.Consensus";
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Consensus.AEDPoS/ConsensusService.Send.cs b/examples/AElf.Client.Consensus.AEDPoS/ConsensusService.Send.cs
new file mode 100644
index 0000000..8c0e783
--- /dev/null
+++ b/examples/AElf.Client.Consensus.AEDPoS/ConsensusService.Send.cs
@@ -0,0 +1,19 @@
+using AElf.Client.Core;
+using AElf.Client.Core.Options;
+using Microsoft.Extensions.Options;
+using Volo.Abp.DependencyInjection;
+
+namespace AElf.Client.Consensus.AEDPoS;
+
+public partial class ConsensusService : ContractServiceBase, IConsensusService, ITransientDependency
+{
+ private readonly IAElfClientService _clientService;
+ private readonly AElfClientConfigOptions _clientConfigOptions;
+
+ public ConsensusService(IAElfClientService clientService, IOptionsSnapshot clientConfigOptions)
+ : base(clientService, AElfConsensusConstants.ConsensusSmartContractName)
+ {
+ _clientService = clientService;
+ _clientConfigOptions = clientConfigOptions.Value;
+ }
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Consensus.AEDPoS/ConsensusService.View.cs b/examples/AElf.Client.Consensus.AEDPoS/ConsensusService.View.cs
new file mode 100644
index 0000000..8e8cf61
--- /dev/null
+++ b/examples/AElf.Client.Consensus.AEDPoS/ConsensusService.View.cs
@@ -0,0 +1,15 @@
+using AElf.Contracts.Consensus.AEDPoS;
+using Google.Protobuf;
+using Google.Protobuf.WellKnownTypes;
+
+namespace AElf.Client.Consensus.AEDPoS;
+
+public partial class ConsensusService
+{
+ public async Task GetCurrentMinerList()
+ {
+ var useClientAlias = _clientConfigOptions.ClientAlias;
+ return await _clientService.ViewSystemAsync(AElfConsensusConstants.ConsensusSmartContractName,
+ "GetCurrentMinerList", new Empty(), useClientAlias);
+ }
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Consensus.AEDPoS/IConsensusService.cs b/examples/AElf.Client.Consensus.AEDPoS/IConsensusService.cs
new file mode 100644
index 0000000..2f0a120
--- /dev/null
+++ b/examples/AElf.Client.Consensus.AEDPoS/IConsensusService.cs
@@ -0,0 +1,8 @@
+using AElf.Contracts.Consensus.AEDPoS;
+
+namespace AElf.Client.Consensus.AEDPoS;
+
+public interface IConsensusService
+{
+ Task GetCurrentMinerList();
+}
\ No newline at end of file
diff --git a/examples/ElectionViewer/ElectionViewer.csproj b/examples/AElf.Client.CrossChain/AElf.Client.CrossChain.csproj
similarity index 64%
rename from examples/ElectionViewer/ElectionViewer.csproj
rename to examples/AElf.Client.CrossChain/AElf.Client.CrossChain.csproj
index b9de063..fa15dcd 100644
--- a/examples/ElectionViewer/ElectionViewer.csproj
+++ b/examples/AElf.Client.CrossChain/AElf.Client.CrossChain.csproj
@@ -1,10 +1,13 @@
- Exe
net6.0
enable
enable
+
+
+
+
diff --git a/examples/AElf.Client.CrossChain/AElfClientCrossChainModule.cs b/examples/AElf.Client.CrossChain/AElfClientCrossChainModule.cs
new file mode 100644
index 0000000..f53ed5f
--- /dev/null
+++ b/examples/AElf.Client.CrossChain/AElfClientCrossChainModule.cs
@@ -0,0 +1,12 @@
+using AElf.Client.Core;
+using Volo.Abp.Modularity;
+
+namespace AElf.Client.CrossChain;
+
+[DependsOn(
+ typeof(AElfClientModule),
+ typeof(CoreAElfModule)
+)]
+public class AElfClientCrossChainModule : AbpModule
+{
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.CrossChain/AElfCrossChainConstants.cs b/examples/AElf.Client.CrossChain/AElfCrossChainConstants.cs
new file mode 100644
index 0000000..3bc30cd
--- /dev/null
+++ b/examples/AElf.Client.CrossChain/AElfCrossChainConstants.cs
@@ -0,0 +1,6 @@
+namespace AElf.Client.CrossChain;
+
+public class AElfCrossChainConstants
+{
+ public const string CrossChainSmartContractName = "AElf.ContractNames.CrossChain";
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.CrossChain/CrossChainService.cs b/examples/AElf.Client.CrossChain/CrossChainService.cs
new file mode 100644
index 0000000..f0a4f72
--- /dev/null
+++ b/examples/AElf.Client.CrossChain/CrossChainService.cs
@@ -0,0 +1,37 @@
+using AElf.Client.Core;
+using AElf.Client.Core.Options;
+using Google.Protobuf;
+using Google.Protobuf.WellKnownTypes;
+using Microsoft.Extensions.Options;
+using Volo.Abp.DependencyInjection;
+
+namespace AElf.Client.CrossChain;
+
+public class CrossChainService : ContractServiceBase, ICrossChainService, ITransientDependency
+{
+ private readonly IAElfClientService _clientService;
+ private readonly AElfClientConfigOptions _clientConfigOptions;
+
+ public CrossChainService(IAElfClientService clientService,
+ IOptionsSnapshot clientConfigOptions) : base(clientService,
+ AElfCrossChainConstants.CrossChainSmartContractName)
+ {
+ _clientService = clientService;
+ _clientConfigOptions = clientConfigOptions.Value;
+ }
+
+ public async Task GetSyncedHeightByChainId(int chainId)
+ {
+ var useClientAlias = _clientConfigOptions.ClientAlias;
+ var height = chainId == AElfClientConstants.MainChainId
+ ? await _clientService.ViewSystemAsync(AElfCrossChainConstants.CrossChainSmartContractName,
+ "GetParentChainHeight",
+ new Empty(), useClientAlias)
+ : await _clientService.ViewSystemAsync(AElfCrossChainConstants.CrossChainSmartContractName,
+ "GetSideChainHeight", new Int32Value
+ {
+ Value = chainId
+ }, useClientAlias);
+ return height.Value;
+ }
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.CrossChain/ICrossChainService.cs b/examples/AElf.Client.CrossChain/ICrossChainService.cs
new file mode 100644
index 0000000..8537c8d
--- /dev/null
+++ b/examples/AElf.Client.CrossChain/ICrossChainService.cs
@@ -0,0 +1,6 @@
+namespace AElf.Client.CrossChain;
+
+public interface ICrossChainService
+{
+ Task GetSyncedHeightByChainId(int chainId);
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Genesis/AElf.Client.Genesis.csproj b/examples/AElf.Client.Genesis/AElf.Client.Genesis.csproj
new file mode 100644
index 0000000..9d89cf5
--- /dev/null
+++ b/examples/AElf.Client.Genesis/AElf.Client.Genesis.csproj
@@ -0,0 +1,20 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/AElf.Client.Genesis/AElfClientGenesisModule.cs b/examples/AElf.Client.Genesis/AElfClientGenesisModule.cs
new file mode 100644
index 0000000..8b33541
--- /dev/null
+++ b/examples/AElf.Client.Genesis/AElfClientGenesisModule.cs
@@ -0,0 +1,22 @@
+using AElf.Client.Consensus.AEDPoS;
+using AElf.Client.Core;
+using AElf.Client.Core.Options;
+using AElf.Client.Parliament;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.Modularity;
+
+namespace AElf.Client.Genesis;
+
+[DependsOn(typeof(AElfClientModule),
+ typeof(CoreAElfModule),
+ typeof(AElfClientParliamentModule),
+ typeof(AElfClientAEDPoSModule))]
+public class AElfClientGenesisModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ var configuration = context.Services.GetConfiguration();
+ Configure(options => { configuration.GetSection("AElfMinerAccount").Bind(options); });
+ }
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Genesis/DeployContractService.cs b/examples/AElf.Client.Genesis/DeployContractService.cs
new file mode 100644
index 0000000..c4523f8
--- /dev/null
+++ b/examples/AElf.Client.Genesis/DeployContractService.cs
@@ -0,0 +1,168 @@
+using AElf.Client.Consensus.AEDPoS;
+using AElf.Client.Core.Infrastructure;
+using AElf.Client.Core.Options;
+using AElf.Client.Parliament;
+using AElf.Standards.ACS0;
+using AElf.Standards.ACS3;
+using AElf.Types;
+using Google.Protobuf;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.Options;
+using Volo.Abp.DependencyInjection;
+
+namespace AElf.Client.Genesis;
+
+public class DeployContractService : IDeployContractService, ITransientDependency
+{
+ private readonly IGenesisService _genesisService;
+ private readonly IParliamentService _parliamentService;
+ private readonly IConsensusService _consensusService;
+
+ private readonly IKeyDirectoryProvider _keyDirectoryProvider;
+ private readonly AElfContractOptions _contractOptions;
+
+ private ILogger Logger { get; set; }
+
+ public DeployContractService(
+ IGenesisService genesisService,
+ IConsensusService consensusService,
+ IParliamentService parliamentService,
+ IKeyDirectoryProvider keyDirectoryProvider,
+ IOptionsSnapshot contractOption)
+ {
+ _parliamentService = parliamentService;
+ _genesisService = genesisService;
+ _consensusService = consensusService;
+ _keyDirectoryProvider = keyDirectoryProvider;
+ _contractOptions = contractOption.Value;
+
+ Logger = NullLogger.Instance;
+ }
+
+ public async Task DeployContractAsync(string contractFileName)
+ {
+ Logger.LogInformation("Deploying contract: {ContractFileName}", contractFileName);
+ var input = await GetContractDeploymentInputAsync(contractFileName);
+ var proposalNewContact = await _genesisService.ProposeNewContract(input);
+ Logger.LogInformation("ProposalNewContact: {Result}", proposalNewContact.TransactionResult);
+ if (proposalNewContact.TransactionResult.Status != TransactionResultStatus.Mined) return null;
+
+ var proposalNewLogs = proposalNewContact.TransactionResult.Logs;
+ var proposalId = ProposalCreated.Parser
+ .ParseFrom(proposalNewLogs.First(l => l.Name.Contains(nameof(ProposalCreated))).NonIndexed)
+ .ProposalId;
+ var proposalHash = ContractProposed.Parser
+ .ParseFrom(proposalNewLogs.First(l => l.Name.Contains(nameof(ContractProposed))).NonIndexed)
+ .ProposedContractInputHash;
+
+ var toBeRelease = await ApproveThroughMinersAsync(proposalId);
+ if (!toBeRelease) return null;
+ var releaseApprovedInput = new ReleaseContractInput
+ {
+ ProposalId = proposalId,
+ ProposedContractInputHash = proposalHash
+ };
+ var releaseApprovedContract = await _genesisService.ReleaseApprovedContract(releaseApprovedInput);
+ Logger.LogInformation("ReleaseApprovedContract: {Result}", releaseApprovedContract.TransactionResult);
+ if (releaseApprovedContract.TransactionResult.Status != TransactionResultStatus.Mined) return null;
+
+ var releaseApprovedLogs = releaseApprovedContract.TransactionResult.Logs;
+ var deployProposalId = ProposalCreated.Parser
+ .ParseFrom(releaseApprovedLogs.First(l => l.Name.Contains(nameof(ProposalCreated))).NonIndexed)
+ .ProposalId;
+
+ var releaseCodeCheckedInput = new ReleaseContractInput
+ {
+ ProposalId = deployProposalId,
+ ProposedContractInputHash = proposalHash
+ };
+
+ if (await CheckProposalAsync(deployProposalId))
+ {
+ var releaseCodeCheckedResult = await _genesisService.ReleaseCodeCheckedContract(releaseCodeCheckedInput);
+ Logger.LogInformation("ReleaseCodeCheckedResult: {Result}", releaseCodeCheckedResult.TransactionResult);
+ if (releaseCodeCheckedResult.TransactionResult.Status != TransactionResultStatus.Mined) return null;
+ var deployAddress = CodeUpdated.Parser.ParseFrom(releaseCodeCheckedResult.TransactionResult.Logs
+ .First(l => l.Name.Contains(nameof(CodeUpdated))).Indexed
+ .First()).Address;
+ Logger.LogInformation($"Contract deploy passed authority, contract address: {deployAddress}");
+ return deployAddress;
+ }
+
+ Logger.LogError("Contract code didn't pass the code check");
+ return null;
+ }
+
+ private async Task GetContractDeploymentInputAsync(string name)
+ {
+ var contractPath = GetFileFullPath(name, _contractOptions.ContractDirectory);
+ var code = await File.ReadAllBytesAsync(contractPath);
+ var checkCode = await CheckCodeAsync(code);
+
+ if (checkCode)
+ {
+ var input = new ContractDeploymentInput
+ {
+ Category = 0,
+ Code = ByteString.CopyFrom(code)
+ };
+ return input;
+ }
+
+ Logger.LogError("The code is already deployed.");
+ return new ContractDeploymentInput();
+ }
+
+ private async Task ApproveThroughMinersAsync(Hash proposalId)
+ {
+ var miners = await _consensusService.GetCurrentMinerList();
+ foreach (var minersPubkey in miners.Pubkeys)
+ {
+ var miner = Address.FromPublicKey(minersPubkey.ToByteArray());
+ var approveResult = await _parliamentService.ApproveAsync(proposalId, miner.ToBase58());
+ Logger.LogInformation("Approve: {Result}", approveResult.TransactionResult);
+ }
+ var toBeRelease = (await _parliamentService.CheckProposal(proposalId)).ToBeReleased;
+ return toBeRelease;
+ }
+
+ private async Task CheckProposalAsync(Hash proposalId)
+ {
+ var toBeReleased = false;
+ var sleepTimes = 0;
+ while (!toBeReleased && sleepTimes < 20)
+ {
+ Thread.Sleep(1000);
+ toBeReleased = (await _parliamentService.CheckProposal(proposalId)).ToBeReleased;
+ Console.Write("\rCheck proposal status");
+ sleepTimes++;
+ }
+
+ return toBeReleased;
+ }
+
+ private string GetFileFullPath(string contractName, string contractFileDirectory)
+ {
+ var dirPath = GetDirectoryPath(contractFileDirectory);
+ var filePath = Path.Combine(dirPath, $"{contractName}.dll");
+ var filePathWithExtension = File.Exists(filePath)
+ ? filePath
+ : Path.Combine(dirPath, $"{contractName}.dll.patched");
+ return filePathWithExtension;
+ }
+
+ private string GetDirectoryPath(string? configuredKeyDirectory)
+ {
+ return string.IsNullOrWhiteSpace(configuredKeyDirectory)
+ ? Path.Combine(_keyDirectoryProvider.GetAppDataPath(), "contracts")
+ : configuredKeyDirectory;
+ }
+
+ private async Task CheckCodeAsync(byte[] code)
+ {
+ var hash = HashHelper.ComputeFrom(code);
+ var registration = await _genesisService.GetSmartContractRegistrationByCodeHash(hash);
+ return registration.Equals(new SmartContractRegistration());
+ }
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Genesis/GenesisService.Send.cs b/examples/AElf.Client.Genesis/GenesisService.Send.cs
new file mode 100644
index 0000000..da4bdd7
--- /dev/null
+++ b/examples/AElf.Client.Genesis/GenesisService.Send.cs
@@ -0,0 +1,73 @@
+using AElf.Client.Core;
+using AElf.Client.Core.Options;
+using AElf.Standards.ACS0;
+using Microsoft.Extensions.Options;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Threading;
+
+namespace AElf.Client.Genesis;
+
+public partial class GenesisService : ContractServiceBase, IGenesisService, ITransientDependency
+{
+ private readonly IAElfClientService _clientService;
+ private readonly AElfClientConfigOptions _clientConfigOptions;
+ private readonly string _contractAddress;
+
+ public GenesisService(IAElfClientService clientService,
+ IOptionsSnapshot clientConfigOptions) : base(clientService,
+ AElfClientCoreConstants.GenesisSmartContractName)
+ {
+ _clientService = clientService;
+ _clientConfigOptions = clientConfigOptions.Value;
+ _contractAddress = AsyncHelper.RunSync(async () =>
+ (await _clientService.GetGenesisContractAddressAsync(_clientConfigOptions.ClientAlias)).ToBase58());
+ }
+
+ public async Task ProposeNewContract(ContractDeploymentInput contractDeploymentInput)
+ {
+ var clientAlias = _clientConfigOptions.ClientAlias;
+ var tx = await _clientService.SendAsync(_contractAddress, "ProposeNewContract", contractDeploymentInput,
+ clientAlias);
+ return new SendTransactionResult
+ {
+ Transaction = tx,
+ TransactionResult = await PerformGetTransactionResultAsync(tx.GetHash().ToHex(), clientAlias)
+ };
+ }
+
+ public async Task ProposeUpdateContract(ContractUpdateInput contractUpdateInput)
+ {
+ var clientAlias = _clientConfigOptions.ClientAlias;
+ var tx = await _clientService.SendAsync(_contractAddress, "ProposeUpdateContract", contractUpdateInput,
+ clientAlias);
+ return new SendTransactionResult
+ {
+ Transaction = tx,
+ TransactionResult = await PerformGetTransactionResultAsync(tx.GetHash().ToHex(), clientAlias)
+ };
+ }
+
+ public async Task ReleaseApprovedContract(ReleaseContractInput releaseContractInput)
+ {
+ var clientAlias = _clientConfigOptions.ClientAlias;
+ var tx = await _clientService.SendAsync(_contractAddress, "ReleaseApprovedContract", releaseContractInput,
+ clientAlias);
+ return new SendTransactionResult
+ {
+ Transaction = tx,
+ TransactionResult = await PerformGetTransactionResultAsync(tx.GetHash().ToHex(), clientAlias)
+ };
+ }
+
+ public async Task ReleaseCodeCheckedContract(ReleaseContractInput releaseContractInput)
+ {
+ var clientAlias = _clientConfigOptions.ClientAlias;
+ var tx = await _clientService.SendAsync(_contractAddress, "ReleaseCodeCheckedContract", releaseContractInput,
+ clientAlias);
+ return new SendTransactionResult
+ {
+ Transaction = tx,
+ TransactionResult = await PerformGetTransactionResultAsync(tx.GetHash().ToHex(), clientAlias)
+ };
+ }
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Genesis/GenesisService.View.cs b/examples/AElf.Client.Genesis/GenesisService.View.cs
new file mode 100644
index 0000000..461c331
--- /dev/null
+++ b/examples/AElf.Client.Genesis/GenesisService.View.cs
@@ -0,0 +1,29 @@
+using AElf.Standards.ACS0;
+using AElf.Types;
+using Google.Protobuf.WellKnownTypes;
+
+namespace AElf.Client.Genesis;
+
+public partial class GenesisService
+{
+ public async Task GetContractDeploymentController()
+ {
+ var useClientAlias = _clientConfigOptions.ClientAlias;
+ return await _clientService.ViewAsync(_contractAddress, "GetContractDeploymentController",
+ new Empty(), useClientAlias);
+ }
+
+ public async Task GetSmartContractRegistrationByCodeHash(Hash codeHash)
+ {
+ var useClientAlias = _clientConfigOptions.ClientAlias;
+ return await _clientService.ViewAsync(_contractAddress,
+ "GetSmartContractRegistrationByCodeHash", codeHash, useClientAlias);
+ }
+
+ public async Task GetContractInfo(Address contractAddress)
+ {
+ var useClientAlias = _clientConfigOptions.ClientAlias;
+ return await _clientService.ViewAsync(_contractAddress, "GetContractInfo",
+ contractAddress, useClientAlias);
+ }
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Genesis/IDeployContractService.cs b/examples/AElf.Client.Genesis/IDeployContractService.cs
new file mode 100644
index 0000000..1a5526c
--- /dev/null
+++ b/examples/AElf.Client.Genesis/IDeployContractService.cs
@@ -0,0 +1,8 @@
+using AElf.Types;
+
+namespace AElf.Client.Genesis;
+
+public interface IDeployContractService
+{
+ Task DeployContractAsync(string contractFileName);
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Genesis/IGenesisService.cs b/examples/AElf.Client.Genesis/IGenesisService.cs
new file mode 100644
index 0000000..178c6e2
--- /dev/null
+++ b/examples/AElf.Client.Genesis/IGenesisService.cs
@@ -0,0 +1,21 @@
+using AElf.Client.Core;
+using AElf.Standards.ACS0;
+using AElf.Types;
+
+namespace AElf.Client.Genesis;
+
+public interface IGenesisService
+{
+ Task ProposeNewContract(ContractDeploymentInput contractDeploymentInput);
+
+ Task ProposeUpdateContract(ContractUpdateInput contractUpdateInput);
+
+ Task ReleaseApprovedContract(ReleaseContractInput releaseContractInput);
+
+ Task ReleaseCodeCheckedContract(ReleaseContractInput releaseContractInput);
+
+
+ Task GetContractDeploymentController();
+ Task GetContractInfo(Address contractAddress);
+ Task GetSmartContractRegistrationByCodeHash(Hash codeHash);
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Parliament/AElf.Client.Parliament.csproj b/examples/AElf.Client.Parliament/AElf.Client.Parliament.csproj
new file mode 100644
index 0000000..08725e2
--- /dev/null
+++ b/examples/AElf.Client.Parliament/AElf.Client.Parliament.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/AElf.Client.Parliament/AElfClientParliamentModule.cs b/examples/AElf.Client.Parliament/AElfClientParliamentModule.cs
new file mode 100644
index 0000000..4e2a703
--- /dev/null
+++ b/examples/AElf.Client.Parliament/AElfClientParliamentModule.cs
@@ -0,0 +1,12 @@
+using AElf.Client.Core;
+using Volo.Abp.Modularity;
+
+namespace AElf.Client.Parliament;
+
+[DependsOn(
+ typeof(AElfClientModule),
+ typeof(CoreAElfModule)
+)]
+public class AElfClientParliamentModule : AbpModule
+{
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Parliament/AElfParliamentConstants.cs b/examples/AElf.Client.Parliament/AElfParliamentConstants.cs
new file mode 100644
index 0000000..1b56bf5
--- /dev/null
+++ b/examples/AElf.Client.Parliament/AElfParliamentConstants.cs
@@ -0,0 +1,6 @@
+namespace AElf.Client.Parliament;
+
+public class AElfParliamentConstants
+{
+ public const string ParliamentSmartContractName = "AElf.ContractNames.Parliament";
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Parliament/IParliamentService.cs b/examples/AElf.Client.Parliament/IParliamentService.cs
new file mode 100644
index 0000000..6676ecc
--- /dev/null
+++ b/examples/AElf.Client.Parliament/IParliamentService.cs
@@ -0,0 +1,16 @@
+using AElf.Client.Core;
+using AElf.Types;
+using AElf.Standards.ACS3;
+using AElf.Contracts.Parliament;
+
+namespace AElf.Client.Parliament;
+
+public interface IParliamentService
+{
+ Task ApproveAsync(Hash proposalId, string accountAddress);
+
+ Task CheckProposal(Hash proposalId);
+
+ Task GetOrganization(Address organizationAddress);
+
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Parliament/Options/AElfMinerAccountOptions.cs b/examples/AElf.Client.Parliament/Options/AElfMinerAccountOptions.cs
new file mode 100644
index 0000000..3be3b5d
--- /dev/null
+++ b/examples/AElf.Client.Parliament/Options/AElfMinerAccountOptions.cs
@@ -0,0 +1,6 @@
+namespace AElf.Client.Core.Options;
+
+public class AElfMinerAccountOptions
+{
+ public string DefaultPassword { get; set; }
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Parliament/ParliamentService.Send.cs b/examples/AElf.Client.Parliament/ParliamentService.Send.cs
new file mode 100644
index 0000000..0bfc3ac
--- /dev/null
+++ b/examples/AElf.Client.Parliament/ParliamentService.Send.cs
@@ -0,0 +1,37 @@
+using AElf.Client.Core;
+using AElf.Client.Core.Options;
+using AElf.Types;
+using Microsoft.Extensions.Options;
+using Volo.Abp.DependencyInjection;
+
+namespace AElf.Client.Parliament;
+
+public partial class ParliamentService : ContractServiceBase, IParliamentService, ITransientDependency
+{
+ private readonly IAElfClientService _clientService;
+ private readonly AElfClientConfigOptions _clientConfigOptions;
+ private readonly IAElfAccountProvider _aelfAccountProvider;
+
+ public ParliamentService(IAElfClientService clientService, IAElfAccountProvider aelfAccountProvider,
+ IOptionsSnapshot clientConfigOptions)
+ : base(clientService, AElfParliamentConstants.ParliamentSmartContractName)
+ {
+ _clientService = clientService;
+ _aelfAccountProvider = aelfAccountProvider;
+ _clientConfigOptions = clientConfigOptions.Value;
+ }
+
+ public async Task ApproveAsync(Hash proposalId, string accountAddress)
+ {
+ var useClientAlias = _clientConfigOptions.ClientAlias;
+ _aelfAccountProvider.AddAccountByDefaultPassword(accountAddress);
+ var accountAlias = _aelfAccountProvider.GetAliasByAddress(accountAddress);
+ var tx = await _clientService.SendSystemAsync(AElfParliamentConstants.ParliamentSmartContractName, "Approve",
+ proposalId, useClientAlias, accountAlias);
+ return new SendTransactionResult
+ {
+ Transaction = tx,
+ TransactionResult = await PerformGetTransactionResultAsync(tx.GetHash().ToHex(), useClientAlias)
+ };
+ }
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Parliament/ParliamentService.View.cs b/examples/AElf.Client.Parliament/ParliamentService.View.cs
new file mode 100644
index 0000000..54d0cf9
--- /dev/null
+++ b/examples/AElf.Client.Parliament/ParliamentService.View.cs
@@ -0,0 +1,23 @@
+using AElf.Contracts.Parliament;
+using AElf.Standards.ACS3;
+using AElf.Types;
+using Google.Protobuf;
+
+namespace AElf.Client.Parliament;
+
+public partial class ParliamentService
+{
+ public async Task CheckProposal(Hash proposalId)
+ {
+ var useClientAlias = _clientConfigOptions.ClientAlias;
+ return await _clientService.ViewSystemAsync(AElfParliamentConstants.ParliamentSmartContractName,
+ "GetProposal", proposalId, useClientAlias);
+ }
+
+ public async Task GetOrganization(Address organizationAddress)
+ {
+ var useClientAlias = _clientConfigOptions.ClientAlias;
+ return await _clientService.ViewSystemAsync(AElfParliamentConstants.ParliamentSmartContractName,
+ "GetOrganization", organizationAddress, useClientAlias);
+ }
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Token/AElf.Client.Token.csproj b/examples/AElf.Client.Token/AElf.Client.Token.csproj
new file mode 100644
index 0000000..13d8a42
--- /dev/null
+++ b/examples/AElf.Client.Token/AElf.Client.Token.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net6.0
+ enable
+ enable
+ AElf.Client.Token
+ AElf token manager abp module.
+ AElf
+ true
+
+
+
+
+
+
+
+
diff --git a/examples/AElf.Client.Token/AElfClientTokenModule.cs b/examples/AElf.Client.Token/AElfClientTokenModule.cs
new file mode 100644
index 0000000..33131ce
--- /dev/null
+++ b/examples/AElf.Client.Token/AElfClientTokenModule.cs
@@ -0,0 +1,32 @@
+using AElf.Client.Core;
+using AElf.Client.Core.Options;
+using AElf.Client.CrossChain;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp;
+using Volo.Abp.Modularity;
+
+namespace AElf.Client.Token;
+
+[DependsOn(
+ typeof(AElfClientModule),
+ typeof(CoreAElfModule),
+ typeof(AElfClientCrossChainModule)
+)]
+public class AElfClientTokenModule : AbpModule
+{
+ public override void ConfigureServices(ServiceConfigurationContext context)
+ {
+ var configuration = context.Services.GetConfiguration();
+ Configure(options => { configuration.GetSection("AElfContract").Bind(options); });
+ }
+
+ public override void OnApplicationInitialization(ApplicationInitializationContext context)
+ {
+ var taskQueueManager = context.ServiceProvider.GetService();
+ taskQueueManager?.CreateQueue(AElfTokenConstants.SyncTokenInfoQueueName,
+ AElfTokenConstants.DefaultMaxDegreeOfParallelism);
+ taskQueueManager?.CreateQueue(AElfTokenConstants.CrossChainTransferQueueName,
+ AElfTokenConstants.DefaultMaxDegreeOfParallelism);
+ }
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Token/AElfTokenConstants.cs b/examples/AElf.Client.Token/AElfTokenConstants.cs
new file mode 100644
index 0000000..4b6f692
--- /dev/null
+++ b/examples/AElf.Client.Token/AElfTokenConstants.cs
@@ -0,0 +1,11 @@
+namespace AElf.Client.Token;
+
+public class AElfTokenConstants
+{
+ public const string TokenSmartContractName = "AElf.ContractNames.Token";
+ public const string SyncTokenInfoQueueName = "SyncTokenInfo";
+ public const string CrossChainTransferQueueName = "CrossChainTransfer";
+ public const int DefaultMaxDegreeOfParallelism = int.MaxValue;
+ public const int TenSeconds = 10_000;
+ public const string TestNetSideChain1MultiTokenContractAddress = "7RzVGiuVWkvL4VfVHdZfQF2Tri3sgLe9U991bohHFfSRZXuGX";
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Token/CrossChainTransfer/CrossChainTransferQueueService.cs b/examples/AElf.Client.Token/CrossChainTransfer/CrossChainTransferQueueService.cs
new file mode 100644
index 0000000..ebf6679
--- /dev/null
+++ b/examples/AElf.Client.Token/CrossChainTransfer/CrossChainTransferQueueService.cs
@@ -0,0 +1,28 @@
+using AElf.Types;
+using Volo.Abp.DependencyInjection;
+
+namespace AElf.Client.Token.CrossChainTransfer;
+
+public class CrossChainTransferQueueService : ICrossChainTransferQueueService, ITransientDependency
+{
+ private readonly ICrossChainTransferService _crossChainTransferService;
+ private readonly ITaskQueueManager _taskQueueManager;
+
+ public CrossChainTransferQueueService(ICrossChainTransferService crossChainTransferService,
+ ITaskQueueManager taskQueueManager)
+ {
+ _crossChainTransferService = crossChainTransferService;
+ _taskQueueManager = taskQueueManager;
+ }
+
+ public void Enqueue(Address to, string symbol, long amount, string fromClientAlias, string toClientAlias)
+ {
+ _taskQueueManager.Enqueue(
+ async () =>
+ {
+ await _crossChainTransferService.CrossChainTransferAsync(to, symbol, amount, fromClientAlias,
+ toClientAlias);
+ },
+ AElfTokenConstants.CrossChainTransferQueueName);
+ }
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Token/CrossChainTransfer/CrossChainTransferService.cs b/examples/AElf.Client.Token/CrossChainTransfer/CrossChainTransferService.cs
new file mode 100644
index 0000000..4fedc66
--- /dev/null
+++ b/examples/AElf.Client.Token/CrossChainTransfer/CrossChainTransferService.cs
@@ -0,0 +1,75 @@
+using AElf.Client.Core;
+using AElf.Client.Core.Options;
+using AElf.Contracts.MultiToken;
+using AElf.Types;
+using Google.Protobuf;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Volo.Abp.DependencyInjection;
+
+namespace AElf.Client.Token.CrossChainTransfer;
+
+public class CrossChainTransferService : ICrossChainTransferService, ITransientDependency
+{
+ private readonly ITokenService _tokenService;
+ private readonly IAElfClientService _clientService;
+ private readonly AElfClientConfigOptions _clientConfigOptions;
+ public ILogger Logger { get; set; }
+
+ public CrossChainTransferService(ITokenService tokenService, IAElfClientService clientService,
+ IOptionsSnapshot clientConfigOptions)
+ {
+ _tokenService = tokenService;
+ _clientService = clientService;
+ _clientConfigOptions = clientConfigOptions.Value;
+ }
+
+ public async Task CrossChainTransferAsync(Address to, string symbol, long amount, string fromClientAlias,
+ string toClientAlias)
+ {
+ var fromChainStatus = await _clientService.GetChainStatusAsync(fromClientAlias);
+ var toChainStatus = await _clientService.GetChainStatusAsync(toClientAlias);
+ var tokenInfo = await _tokenService.GetTokenInfoAsync(symbol);
+ var crossChainTransferInput = new CrossChainTransferInput
+ {
+ To = to,
+ Symbol = symbol,
+ Amount = amount,
+ ToChainId = ChainHelper.ConvertBase58ToChainId(toChainStatus.ChainId),
+ IssueChainId = tokenInfo.IssueChainId
+ };
+ var transferResult = await _tokenService.CrossChainTransferAsync(crossChainTransferInput, fromClientAlias);
+ Logger.LogInformation("CrossChainTransfer: {Result}", transferResult.TransactionResult);
+ if (transferResult.TransactionResult.Status == TransactionResultStatus.Mined)
+ {
+ while (true)
+ {
+ var chainStatus =
+ await _clientService.GetChainStatusAsync(fromClientAlias);
+ Logger.LogInformation(
+ "From chain lib height: {LibHeight}, Transfer tx package height: {TransferHeight}",
+ chainStatus.LastIrreversibleBlockHeight, transferResult.TransactionResult.BlockNumber);
+ if (chainStatus.LastIrreversibleBlockHeight - transferResult.TransactionResult.BlockNumber > 300)
+ break;
+ await Task.Delay(AElfTokenConstants.TenSeconds);
+ }
+
+ var merklePath = await _clientService.GetMerklePathByTransactionIdAsync(
+ transferResult.TransactionResult.TransactionId.ToHex(),
+ fromClientAlias);
+ var crossChainReceiveTokenInput = new CrossChainReceiveTokenInput
+ {
+ FromChainId = ChainHelper.ConvertBase58ToChainId(fromChainStatus.ChainId),
+ MerklePath = merklePath,
+ ParentChainHeight = transferResult.TransactionResult.BlockNumber,
+ TransferTransactionBytes =
+ ByteString.CopyFrom(
+ ByteArrayHelper.HexStringToByteArray(transferResult.Transaction.ToByteArray().ToHex())),
+ };
+
+ var crossChainReceiveTokenResult =
+ await _tokenService.CrossChainReceiveTokenAsync(crossChainReceiveTokenInput, toClientAlias);
+ Logger.LogInformation("CrossChainReceiveToken: {Result}", crossChainReceiveTokenResult.TransactionResult);
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Token/CrossChainTransfer/ICrossChainTransferQueueService.cs b/examples/AElf.Client.Token/CrossChainTransfer/ICrossChainTransferQueueService.cs
new file mode 100644
index 0000000..794a13e
--- /dev/null
+++ b/examples/AElf.Client.Token/CrossChainTransfer/ICrossChainTransferQueueService.cs
@@ -0,0 +1,8 @@
+using AElf.Types;
+
+namespace AElf.Client.Token.CrossChainTransfer;
+
+public interface ICrossChainTransferQueueService
+{
+ void Enqueue(Address to, string symbol, long amount, string fromClientAlias, string toClientAlias);
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Token/CrossChainTransfer/ICrossChainTransferService.cs b/examples/AElf.Client.Token/CrossChainTransfer/ICrossChainTransferService.cs
new file mode 100644
index 0000000..bcfdb65
--- /dev/null
+++ b/examples/AElf.Client.Token/CrossChainTransfer/ICrossChainTransferService.cs
@@ -0,0 +1,8 @@
+using AElf.Types;
+
+namespace AElf.Client.Token.CrossChainTransfer;
+
+public interface ICrossChainTransferService
+{
+ Task CrossChainTransferAsync(Address to, string symbol, long amount, string fromClientAlias, string toClientAlias);
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Token/ITokenService.cs b/examples/AElf.Client.Token/ITokenService.cs
new file mode 100644
index 0000000..f971e55
--- /dev/null
+++ b/examples/AElf.Client.Token/ITokenService.cs
@@ -0,0 +1,33 @@
+using AElf.Client.Core;
+using AElf.Contracts.Bridge;
+using AElf.Contracts.MultiToken;
+using AElf.Contracts.NFT;
+using AElf.Types;
+using TransferInput = AElf.Contracts.MultiToken.TransferInput;
+
+namespace AElf.Client.Token;
+
+public interface ITokenService
+{
+ Task CreateTokenAsync(Contracts.MultiToken.CreateInput createInput);
+ Task CreateNFTProtocolAsync(Contracts.NFT.CreateInput createInput);
+ Task MintNFTAsync(MintInput mintInput);
+ Task ValidateTokenInfoExistsAsync(ValidateTokenInfoExistsInput validateTokenInfoExistsInput);
+ Task CrossChainCreateTokenAsync(CrossChainCreateTokenInput crossChainCreateTokenInput);
+ Task CrossChainTransferAsync(CrossChainTransferInput crossChainTransferInput,
+ string clientAlias);
+ Task CrossChainReceiveTokenAsync(CrossChainReceiveTokenInput crossChainReceiveTokenInput,
+ string clientAlias);
+
+ Task CrossChainCreateNFTProtocolAsync(CrossChainCreateInput crossChainCreateInput);
+
+ Task TransferAsync(TransferInput transferInput);
+
+ Task AddMintersAsync(AddMintersInput addMintersInput);
+ Task SwapTokenAsync(SwapTokenInput swapTokenInput);
+
+ Task GetTokenInfoAsync(string symbol);
+ Task GetTokenBalanceAsync(string symbol, Address owner);
+ Task GetTokenAllowanceAsync(string symbol, Address owner, Address spender);
+ Task GetCalculateFeeCoefficientsForSenderAsync();
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Token/README.md b/examples/AElf.Client.Token/README.md
new file mode 100644
index 0000000..a7c2a45
--- /dev/null
+++ b/examples/AElf.Client.Token/README.md
@@ -0,0 +1,4 @@
+# AElf Client TokenManager
+Some useful methods to interact with:
+- [AElf MultiToken Contract](https://github.com/AElfProject/AElf/tree/dev/contract/AElf.Contracts.MultiToken)
+- [AElf NFT Contract](https://github.com/AElfProject/AElf/tree/dev/contract/AElf.Contracts.NFT)
diff --git a/examples/AElf.Client.Token/SyncTokenInfo/ISyncTokenInfoQueueService.cs b/examples/AElf.Client.Token/SyncTokenInfo/ISyncTokenInfoQueueService.cs
new file mode 100644
index 0000000..6f28907
--- /dev/null
+++ b/examples/AElf.Client.Token/SyncTokenInfo/ISyncTokenInfoQueueService.cs
@@ -0,0 +1,6 @@
+namespace AElf.Client.Token.SyncTokenInfo;
+
+public interface ISyncTokenInfoQueueService
+{
+ void Enqueue(string symbol);
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Token/SyncTokenInfo/ISyncTokenInfoService.cs b/examples/AElf.Client.Token/SyncTokenInfo/ISyncTokenInfoService.cs
new file mode 100644
index 0000000..8ebb3ff
--- /dev/null
+++ b/examples/AElf.Client.Token/SyncTokenInfo/ISyncTokenInfoService.cs
@@ -0,0 +1,6 @@
+namespace AElf.Client.Token.SyncTokenInfo;
+
+public interface ISyncTokenInfoService
+{
+ Task SyncTokenInfoAsync(string symbol);
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Token/SyncTokenInfo/SyncTokenInfoQueueService.cs b/examples/AElf.Client.Token/SyncTokenInfo/SyncTokenInfoQueueService.cs
new file mode 100644
index 0000000..c6d506e
--- /dev/null
+++ b/examples/AElf.Client.Token/SyncTokenInfo/SyncTokenInfoQueueService.cs
@@ -0,0 +1,22 @@
+using Volo.Abp.DependencyInjection;
+
+namespace AElf.Client.Token.SyncTokenInfo;
+
+public class SyncTokenInfoQueueService : ISyncTokenInfoQueueService, ITransientDependency
+{
+ private readonly ISyncTokenInfoService _syncTokenInfoService;
+ private readonly ITaskQueueManager _taskQueueManager;
+
+ public SyncTokenInfoQueueService(ISyncTokenInfoService syncTokenInfoService,
+ ITaskQueueManager taskQueueManager)
+ {
+ _syncTokenInfoService = syncTokenInfoService;
+ _taskQueueManager = taskQueueManager;
+ }
+
+ public void Enqueue(string symbol)
+ {
+ _taskQueueManager.Enqueue(async () => { await _syncTokenInfoService.SyncTokenInfoAsync(symbol); },
+ AElfTokenConstants.SyncTokenInfoQueueName);
+ }
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Token/SyncTokenInfo/SyncTokenInfoService.cs b/examples/AElf.Client.Token/SyncTokenInfo/SyncTokenInfoService.cs
new file mode 100644
index 0000000..930c8e5
--- /dev/null
+++ b/examples/AElf.Client.Token/SyncTokenInfo/SyncTokenInfoService.cs
@@ -0,0 +1,86 @@
+using AElf.Client.Core;
+using AElf.Client.Core.Options;
+using AElf.Client.CrossChain;
+using AElf.Contracts.MultiToken;
+using AElf.Types;
+using Google.Protobuf;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.Options;
+using Volo.Abp.DependencyInjection;
+
+namespace AElf.Client.Token.SyncTokenInfo;
+
+public class SyncTokenInfoService : ISyncTokenInfoService, ITransientDependency
+{
+ private readonly ITokenService _tokenService;
+ private readonly ICrossChainService _crossChainService;
+ private readonly IAElfClientService _clientService;
+ private readonly AElfClientConfigOptions _clientConfigOptions;
+ public ILogger Logger { get; set; }
+
+ public SyncTokenInfoService(ITokenService tokenService, ICrossChainService crossChainService,
+ IAElfClientService clientService, IOptionsSnapshot clientConfigOptions)
+ {
+ _tokenService = tokenService;
+ _crossChainService = crossChainService;
+ _clientService = clientService;
+ _clientConfigOptions = clientConfigOptions.Value;
+
+ Logger = NullLogger.Instance;
+ }
+
+ public async Task SyncTokenInfoAsync(string symbol)
+ {
+ var tokenInfo = await _tokenService.GetTokenInfoAsync(symbol);
+ var validateInput = new ValidateTokenInfoExistsInput
+ {
+ Symbol = tokenInfo.Symbol,
+ TokenName = tokenInfo.TokenName,
+ Decimals = tokenInfo.Decimals,
+ IsBurnable = tokenInfo.IsBurnable,
+ IssueChainId = tokenInfo.IssueChainId,
+ Issuer = tokenInfo.Issuer,
+ TotalSupply = tokenInfo.TotalSupply,
+ ExternalInfo = { tokenInfo.ExternalInfo.Value }
+ };
+
+ var validateResult = await _tokenService.ValidateTokenInfoExistsAsync(validateInput);
+ var packagedBlockHeight = validateResult.TransactionResult.BlockNumber;
+ Logger.LogInformation("ValidateTokenInfoExists: {Result}", validateResult.TransactionResult);
+ if (validateResult.TransactionResult.Status == TransactionResultStatus.Mined)
+ {
+ while (true)
+ {
+ var syncedMainChainHeight =
+ await _crossChainService.GetSyncedHeightByChainId(AElfClientConstants.MainChainId);
+ Logger.LogInformation(
+ "Synced main chain height: {MainChainHeight}, Validate tx package height: {ValidateHeight}",
+ syncedMainChainHeight, validateResult.TransactionResult.BlockNumber);
+ if (syncedMainChainHeight >= packagedBlockHeight)
+ {
+ break;
+ }
+
+ await Task.Delay(AElfTokenConstants.TenSeconds);
+ }
+
+ var merklePath = await _clientService.GetMerklePathByTransactionIdAsync(
+ validateResult.TransactionResult.TransactionId.ToHex(),
+ _clientConfigOptions.MainChainClientAlias);
+ var crossChainCreateTokenInput = new CrossChainCreateTokenInput
+ {
+ FromChainId = AElfClientConstants.MainChainId,
+ ParentChainHeight = validateResult.TransactionResult.BlockNumber,
+ TransactionBytes =
+ ByteString.CopyFrom(
+ ByteArrayHelper.HexStringToByteArray(validateResult.Transaction.ToByteArray().ToHex())),
+ MerklePath = merklePath
+ };
+
+ var crossChainCreateTokenResult =
+ await _tokenService.CrossChainCreateTokenAsync(crossChainCreateTokenInput);
+ Logger.LogInformation("CrossChainCreateToken: {Result}", crossChainCreateTokenResult.TransactionResult);
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Token/TokenService.Send.cs b/examples/AElf.Client.Token/TokenService.Send.cs
new file mode 100644
index 0000000..15cfcfc
--- /dev/null
+++ b/examples/AElf.Client.Token/TokenService.Send.cs
@@ -0,0 +1,177 @@
+using AElf.Client.Core;
+using AElf.Client.Core.Options;
+using AElf.Contracts.Bridge;
+using AElf.Contracts.MultiToken;
+using AElf.Contracts.NFT;
+using AElf.Types;
+using Microsoft.Extensions.Options;
+using Volo.Abp.DependencyInjection;
+using CreateInput = AElf.Contracts.MultiToken.CreateInput;
+using TransferInput = AElf.Contracts.MultiToken.TransferInput;
+
+namespace AElf.Client.Token;
+
+public partial class TokenService : ContractServiceBase, ITokenService, ITransientDependency
+{
+ private readonly IAElfClientService _clientService;
+ private readonly AElfContractOptions _contractOptions;
+ private readonly AElfClientConfigOptions _clientConfigOptions;
+
+ public TokenService(IAElfClientService clientService, IOptionsSnapshot clientConfigOptions,
+ IOptionsSnapshot contractOptions) : base(clientService,
+ AElfTokenConstants.TokenSmartContractName)
+ {
+ _clientService = clientService;
+ _contractOptions = contractOptions.Value;
+ _clientConfigOptions = clientConfigOptions.Value;
+ }
+
+ public async Task CreateTokenAsync(CreateInput createInput)
+ {
+ var clientAlias = PreferGetUseMainChainClientAlias();
+ var tx = await PerformSendTransactionAsync("Create", createInput, clientAlias);
+ return new SendTransactionResult
+ {
+ Transaction = tx,
+ TransactionResult = await PerformGetTransactionResultAsync(tx.GetHash().ToHex(), clientAlias)
+ };
+ }
+
+ public async Task CreateNFTProtocolAsync(Contracts.NFT.CreateInput createInput)
+ {
+ var clientAlias = PreferGetUseMainChainClientAlias();
+ var tx = await PerformSendTransactionAsync("Create", createInput, clientAlias);
+ return new SendTransactionResult
+ {
+ Transaction = tx,
+ TransactionResult = await PerformGetTransactionResultAsync(tx.GetHash().ToHex(), clientAlias)
+ };
+ }
+
+ public async Task MintNFTAsync(MintInput mintInput)
+ {
+ var clientAlias = _clientConfigOptions.ClientAlias;
+ var tx = await PerformSendTransactionAsync("Mint", mintInput, clientAlias);
+ return new SendTransactionResult
+ {
+ Transaction = tx,
+ TransactionResult = await PerformGetTransactionResultAsync(tx.GetHash().ToHex(), clientAlias)
+ };
+ }
+
+ public async Task ValidateTokenInfoExistsAsync(
+ ValidateTokenInfoExistsInput validateTokenInfoExistsInput)
+ {
+ var clientAlias = PreferGetUseMainChainClientAlias();
+ var tx = await PerformSendTransactionAsync("ValidateTokenInfoExists", validateTokenInfoExistsInput,
+ clientAlias);
+ return new SendTransactionResult
+ {
+ Transaction = tx,
+ TransactionResult = await PerformGetTransactionResultAsync(tx.GetHash().ToHex(), clientAlias)
+ };
+ }
+
+ public async Task CrossChainCreateTokenAsync(
+ CrossChainCreateTokenInput crossChainCreateTokenInput)
+ {
+ var clientAlias = PreferGetUseSideChainClientAlias();
+ var tx = await PerformSendTransactionAsync("CrossChainCreateToken", crossChainCreateTokenInput, clientAlias);
+ return new SendTransactionResult
+ {
+ Transaction = tx,
+ TransactionResult = await PerformGetTransactionResultAsync(tx.GetHash().ToHex(), clientAlias)
+ };
+ }
+
+ public async Task CrossChainTransferAsync(CrossChainTransferInput crossChainTransferInput,
+ string clientAlias)
+ {
+ var tx = await _clientService.SendSystemAsync(AElfTokenConstants.TokenSmartContractName, "CrossChainTransfer",
+ crossChainTransferInput, clientAlias);
+ return new SendTransactionResult
+ {
+ Transaction = tx,
+ TransactionResult = await PerformGetTransactionResultAsync(tx.GetHash().ToHex(), clientAlias)
+ };
+ }
+
+ public async Task CrossChainReceiveTokenAsync(
+ CrossChainReceiveTokenInput crossChainReceiveTokenInput, string clientAlias)
+ {
+ var tx = await PerformSendTransactionAsync("CrossChainReceiveToken", crossChainReceiveTokenInput,
+ clientAlias);
+ return new SendTransactionResult
+ {
+ Transaction = tx,
+ TransactionResult = await PerformGetTransactionResultAsync(tx.GetHash().ToHex(), clientAlias)
+ };
+ }
+
+ public async Task CrossChainCreateNFTProtocolAsync(
+ CrossChainCreateInput crossChainCreateInput)
+ {
+ var clientAlias = PreferGetUseSideChainClientAlias();
+ ContractAddress = Address.FromBase58(_contractOptions.ContractAddressList["NFTContract"]);
+ var tx = await PerformSendTransactionAsync("CrossChainCreate", crossChainCreateInput,
+ clientAlias);
+ return new SendTransactionResult
+ {
+ Transaction = tx,
+ TransactionResult = await PerformGetTransactionResultAsync(tx.GetHash().ToHex(), clientAlias)
+ };
+ }
+
+ public async Task TransferAsync(TransferInput transferInput)
+ {
+ var clientAlias = _clientConfigOptions.ClientAlias;
+ var tx = await PerformSendTransactionAsync("Transfer", transferInput,
+ clientAlias);
+ return new SendTransactionResult
+ {
+ Transaction = tx,
+ TransactionResult = await PerformGetTransactionResultAsync(tx.GetHash().ToHex(), clientAlias)
+ };
+ }
+
+ public async Task AddMintersAsync(AddMintersInput addMintersInput)
+ {
+ var clientAlias = _clientConfigOptions.ClientAlias;
+ ContractAddress = Address.FromBase58(_contractOptions.ContractAddressList["NFTContract"]);
+ var tx = await PerformSendTransactionAsync("AddMinters", addMintersInput,
+ clientAlias);
+ return new SendTransactionResult
+ {
+ Transaction = tx,
+ TransactionResult = await PerformGetTransactionResultAsync(tx.GetHash().ToHex(), clientAlias)
+ };
+ }
+
+ public async Task SwapTokenAsync(SwapTokenInput swapTokenInput)
+ {
+ var clientAlias = _clientConfigOptions.ClientAlias;
+ ContractAddress = Address.FromBase58(_contractOptions.ContractAddressList["BridgeContract"]);
+ var tx = await PerformSendTransactionAsync("SwapToken", swapTokenInput,
+ clientAlias);
+ var txResult = await PerformGetTransactionResultAsync(tx.GetHash().ToHex(), clientAlias);
+ return new SendTransactionResult
+ {
+ Transaction = tx,
+ TransactionResult = txResult
+ };
+ }
+
+ private string PreferGetUseMainChainClientAlias()
+ {
+ return !string.IsNullOrEmpty(_clientConfigOptions.MainChainClientAlias)
+ ? _clientConfigOptions.MainChainClientAlias
+ : _clientConfigOptions.ClientAlias;
+ }
+
+ private string PreferGetUseSideChainClientAlias()
+ {
+ return !string.IsNullOrEmpty(_clientConfigOptions.SideChainClientAlias)
+ ? _clientConfigOptions.SideChainClientAlias
+ : _clientConfigOptions.ClientAlias;
+ }
+}
\ No newline at end of file
diff --git a/examples/AElf.Client.Token/TokenService.View.cs b/examples/AElf.Client.Token/TokenService.View.cs
new file mode 100644
index 0000000..a98257b
--- /dev/null
+++ b/examples/AElf.Client.Token/TokenService.View.cs
@@ -0,0 +1,50 @@
+using AElf.Contracts.MultiToken;
+using AElf.Types;
+using Google.Protobuf;
+using Google.Protobuf.WellKnownTypes;
+using Microsoft.Extensions.Logging;
+
+namespace AElf.Client.Token;
+
+public partial class TokenService
+{
+ public async Task GetTokenInfoAsync(string symbol)
+ {
+ var useClientAlias = _clientConfigOptions.ClientAlias;
+ return await _clientService.ViewSystemAsync(AElfTokenConstants.TokenSmartContractName,
+ "GetTokenInfo", new GetTokenInfoInput
+ {
+ Symbol = symbol
+ }, useClientAlias);
+ }
+
+ public async Task GetTokenBalanceAsync(string symbol, Address owner)
+ {
+ var useClientAlias = _clientConfigOptions.ClientAlias;
+ return await _clientService.ViewSystemAsync(AElfTokenConstants.TokenSmartContractName,
+ "GetBalance", new GetBalanceInput
+ {
+ Owner = owner,
+ Symbol = symbol
+ }, useClientAlias);
+ }
+
+ public async Task GetTokenAllowanceAsync(string symbol, Address owner, Address spender)
+ {
+ var useClientAlias = _clientConfigOptions.ClientAlias;
+ return await _clientService.ViewSystemAsync(AElfTokenConstants.TokenSmartContractName,
+ "GetAllowance", new GetAllowanceInput
+ {
+ Owner = owner,
+ Spender = spender,
+ Symbol = symbol
+ }, useClientAlias);
+ }
+
+ public async Task GetCalculateFeeCoefficientsForSenderAsync()
+ {
+ var useClientAlias = _clientConfigOptions.ClientAlias;
+ return await _clientService.ViewSystemAsync(AElfTokenConstants.TokenSmartContractName,
+ "GetCalculateFeeCoefficientsForSender", new Empty(), useClientAlias);
+ }
+}
\ No newline at end of file
diff --git a/examples/ElectionViewer/Program.cs b/examples/ElectionViewer/Program.cs
deleted file mode 100644
index e5dff12..0000000
--- a/examples/ElectionViewer/Program.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-// See https://aka.ms/new-console-template for more information
-
-Console.WriteLine("Hello, World!");
\ No newline at end of file
diff --git a/examples/TokenManager/Program.cs b/examples/TokenManager/Program.cs
deleted file mode 100644
index e5dff12..0000000
--- a/examples/TokenManager/Program.cs
+++ /dev/null
@@ -1,3 +0,0 @@
-// See https://aka.ms/new-console-template for more information
-
-Console.WriteLine("Hello, World!");
\ No newline at end of file
diff --git a/src/AElf.Client.Abp/AElfClientService.cs b/src/AElf.Client.Abp/AElfClientService.cs
deleted file mode 100644
index 734cbb7..0000000
--- a/src/AElf.Client.Abp/AElfClientService.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using AElf.Client.Dto;
-using Google.Protobuf;
-using Volo.Abp.DependencyInjection;
-
-namespace AElf.Client.Abp;
-
-public class AElfClientService : IAElfClientService, ITransientDependency
-{
- private readonly IAElfClientProvider _aelfClientProvider;
- private readonly IAElfAccountProvider _aelfAccountProvider;
-
- public AElfClientService(IAElfClientProvider aelfClientProvider, IAElfAccountProvider aelfAccountProvider)
- {
- _aelfClientProvider = aelfClientProvider;
- _aelfAccountProvider = aelfAccountProvider;
- }
-
- public async Task ViewAsync(string contractAddress, string methodName, IMessage parameter, string clientAlias,
- string accountAlias = "Default")
- {
- var aelfClient = _aelfClientProvider.GetClient(alias: clientAlias);
- var aelfAccount = _aelfAccountProvider.GetPrivateKey(alias: accountAlias);
- var tx = new TransactionBuilder(aelfClient)
- .UsePrivateKey(aelfAccount)
- .UseContract(contractAddress)
- .UseMethod(methodName)
- .UseParameter(parameter)
- .Build();
- return await PerformViewAsync(aelfClient, tx);
- }
-
- public async Task ViewSystemAsync(string systemContractName, string methodName, IMessage parameter, string clientAlias,
- string accountAlias = "Default")
- {
- var aelfClient = _aelfClientProvider.GetClient(alias: clientAlias);
- var privateKey = _aelfAccountProvider.GetPrivateKey(alias: accountAlias);
- var tx = new TransactionBuilder(aelfClient)
- .UsePrivateKey(privateKey)
- .UseSystemContract(systemContractName)
- .UseMethod(methodName)
- .UseParameter(parameter)
- .Build();
- return await PerformViewAsync(aelfClient, tx);
- }
-
- private async Task PerformViewAsync(AElfClient aelfClient, Transaction tx)
- {
- var result = await aelfClient.ExecuteTransactionAsync(new ExecuteTransactionDto
- {
- RawTransaction = tx.ToByteArray().ToHex()
- });
- return ByteArrayHelper.HexStringToByteArray(result);
- }
-}
\ No newline at end of file
diff --git a/src/AElf.Client.Abp/IAElfClientService.cs b/src/AElf.Client.Abp/IAElfClientService.cs
deleted file mode 100644
index 3d126f5..0000000
--- a/src/AElf.Client.Abp/IAElfClientService.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using Google.Protobuf;
-
-namespace AElf.Client;
-
-public interface IAElfClientService
-{
- Task ViewAsync(string contractAddress, string methodName, IMessage parameter, string clientAlias,
- string accountAlias = "Default");
-
- Task ViewSystemAsync(string systemContractName, string methodName, IMessage parameter,
- string clientAlias, string accountAlias = "Default");
-}
\ No newline at end of file
diff --git a/src/AElf.Client.Abp/AElf.Client.Abp.csproj b/src/AElf.Client.Core/AElf.Client.Core.csproj
similarity index 53%
rename from src/AElf.Client.Abp/AElf.Client.Abp.csproj
rename to src/AElf.Client.Core/AElf.Client.Core.csproj
index 2f6815f..f048d05 100644
--- a/src/AElf.Client.Abp/AElf.Client.Abp.csproj
+++ b/src/AElf.Client.Core/AElf.Client.Core.csproj
@@ -4,18 +4,21 @@
net6.0
enable
enable
- AElf.Client.Abp
- C# sdk with abp module.
+ AElf.Client.Core
+ AElf C# sdk with abp module.
AElf
true
+ AElf.Client.Core
-
+
+
+
-
+
-
+
diff --git a/src/AElf.Client.Core/AElfClientCoreConstants.cs b/src/AElf.Client.Core/AElfClientCoreConstants.cs
new file mode 100644
index 0000000..a090699
--- /dev/null
+++ b/src/AElf.Client.Core/AElfClientCoreConstants.cs
@@ -0,0 +1,7 @@
+namespace AElf.Client.Core;
+
+public class AElfClientCoreConstants
+{
+ public const int DefaultWaitMilliseconds = 100;
+ public const string GenesisSmartContractName = "AElf.ContractNames.Genesis";
+}
\ No newline at end of file
diff --git a/src/AElf.Client.Abp/AElfClientModule.cs b/src/AElf.Client.Core/AElfClientModule.cs
similarity index 50%
rename from src/AElf.Client.Abp/AElfClientModule.cs
rename to src/AElf.Client.Core/AElfClientModule.cs
index 95cfe53..700356e 100644
--- a/src/AElf.Client.Abp/AElfClientModule.cs
+++ b/src/AElf.Client.Core/AElfClientModule.cs
@@ -1,13 +1,15 @@
-using AElf.Client.Options;
+using AElf.Client.Core.Options;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Autofac;
+using Volo.Abp.AutoMapper;
using Volo.Abp.Modularity;
-namespace AElf.Client.Abp;
+namespace AElf.Client.Core;
[DependsOn(
- typeof(AbpAutofacModule)
+ typeof(AbpAutofacModule),
+ typeof(AbpAutoMapperModule)
)]
public class AElfClientModule : AbpModule
{
@@ -16,5 +18,14 @@ public override void ConfigureServices(ServiceConfigurationContext context)
var configuration = context.Services.GetConfiguration();
Configure(options => { configuration.GetSection("AElfClient").Bind(options); });
Configure(options => { configuration.GetSection("AElfAccount").Bind(options); });
+ Configure(options => { configuration.GetSection("AElfContract").Bind(options); });
+ Configure(options => { configuration.GetSection("AElfClientConfig").Bind(options); });
+
+ context.Services.AddAutoMapperObjectMapper();
+
+ Configure(options =>
+ {
+ options.AddMaps();
+ });
}
}
\ No newline at end of file
diff --git a/src/AElf.Client.Core/AElfClientService.Blockchain.cs b/src/AElf.Client.Core/AElfClientService.Blockchain.cs
new file mode 100644
index 0000000..5256706
--- /dev/null
+++ b/src/AElf.Client.Core/AElfClientService.Blockchain.cs
@@ -0,0 +1,63 @@
+using AElf.Client.Dto;
+using Google.Protobuf;
+using Google.Protobuf.Reflection;
+using Microsoft.Extensions.Logging;
+
+namespace AElf.Client.Core;
+
+public partial class AElfClientService
+{
+ public async Task GetTransactionResultAsync(string transactionId, string clientAlias)
+ {
+ var aelfClient = _aelfClientProvider.GetClient(alias: clientAlias);
+ var result = await aelfClient.GetTransactionResultAsync(transactionId);
+ var i = 0;
+ while (i < 10)
+ {
+ if (result!.Status == TransactionResultStatus.Mined.ToString().ToUpper())
+ {
+ break;
+ }
+
+ if (result.Status == TransactionResultStatus.Failed.ToString().ToUpper() ||
+ result.Status == TransactionResultStatus.NodeValidationFailed.ToString().ToUpper())
+ {
+ break;
+ }
+
+ await Task.Delay(AElfClientCoreConstants.DefaultWaitMilliseconds);
+ result = await aelfClient.GetTransactionResultAsync(transactionId);
+ i++;
+ }
+
+ return _objectMapper.Map(result!);
+ }
+
+ public async Task GetChainStatusAsync(string clientAlias)
+ {
+ var aelfClient = _aelfClientProvider.GetClient(alias: clientAlias);
+ return await aelfClient.GetChainStatusAsync();
+ }
+
+ public async Task GetMerklePathByTransactionIdAsync(string transactionId, string clientAlias)
+ {
+ var aelfClient = _aelfClientProvider.GetClient(alias: clientAlias);
+ var merklePathDto = await aelfClient.GetMerklePathByTransactionIdAsync(transactionId);
+ if (merklePathDto == null)
+ {
+ Logger.LogError("Cannot get merkle path of transaction {TransactionId}", transactionId);
+ merklePathDto = new MerklePathDto();
+ }
+
+ return _objectMapper.Map(merklePathDto);
+ }
+
+ public async Task GetContractFileDescriptorSetAsync(string contractAddress, string clientAlias)
+ {
+ var aelfClient = _aelfClientProvider.GetClient(alias: clientAlias);
+ var result = await aelfClient.GetContractFileDescriptorSetAsync(contractAddress);
+ var fileDescriptorSet = new FileDescriptorSet();
+ fileDescriptorSet.MergeFrom(result);
+ return fileDescriptorSet;
+ }
+}
\ No newline at end of file
diff --git a/src/AElf.Client.Core/AElfClientService.Send.cs b/src/AElf.Client.Core/AElfClientService.Send.cs
new file mode 100644
index 0000000..6cd9395
--- /dev/null
+++ b/src/AElf.Client.Core/AElfClientService.Send.cs
@@ -0,0 +1,57 @@
+using AElf.Client.Dto;
+using AElf.Client.Services;
+using Google.Protobuf;
+
+namespace AElf.Client.Core;
+
+public partial class AElfClientService
+{
+ public async Task SendAsync(string contractAddress, string methodName, IMessage parameter,
+ string clientAlias, string? accountAlias = null)
+ {
+ var aelfClient = _aelfClientProvider.GetClient(alias: clientAlias);
+ var aelfAccount = _aelfAccountProvider.GetPrivateKey(alias: _clientConfigOptions.AccountAlias);
+ var tx = new TransactionBuilder(aelfClient)
+ .UsePrivateKey(aelfAccount)
+ .UseContract(contractAddress)
+ .UseMethod(methodName)
+ .UseParameter(parameter)
+ .Build();
+ await PerformSendAsync(aelfClient, tx);
+ return tx;
+ }
+
+ public async Task SendSystemAsync(string systemContractName, string methodName, IMessage parameter,
+ string clientAlias, string? accountAlias = null)
+ {
+ if (!systemContractName.StartsWith("AElf.ContractNames."))
+ {
+ throw new ArgumentException("Invalid system contract name.");
+ }
+
+ if (systemContractName == AElfClientCoreConstants.GenesisSmartContractName)
+ {
+ return await SendAsync((await GetGenesisContractAddressAsync(clientAlias)).ToBase58(), methodName,
+ parameter, clientAlias, accountAlias);
+ }
+
+ var aelfClient = _aelfClientProvider.GetClient(alias: clientAlias);
+ var aelfAccount = _aelfAccountProvider.GetPrivateKey(alias: _clientConfigOptions.AccountAlias);
+ var tx = new TransactionBuilder(aelfClient)
+ .UsePrivateKey(aelfAccount)
+ .UseSystemContract(systemContractName)
+ .UseMethod(methodName)
+ .UseParameter(parameter)
+ .Build();
+ await PerformSendAsync(aelfClient, tx);
+ return tx;
+ }
+
+ private static async Task PerformSendAsync(ITransactionAppService aelfClient, Transaction tx)
+ {
+ await aelfClient.SendTransactionAsync(new SendTransactionInput
+ {
+ RawTransaction = tx.ToByteArray().ToHex()
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/AElf.Client.Core/AElfClientService.View.cs b/src/AElf.Client.Core/AElfClientService.View.cs
new file mode 100644
index 0000000..278ff3b
--- /dev/null
+++ b/src/AElf.Client.Core/AElfClientService.View.cs
@@ -0,0 +1,87 @@
+using AElf.Client.Dto;
+using AElf.Client.Core.Options;
+using AElf.Client.Services;
+using Google.Protobuf;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.Options;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.ObjectMapping;
+
+namespace AElf.Client.Core;
+
+public partial class AElfClientService : IAElfClientService, ITransientDependency
+{
+ private readonly IAElfClientProvider _aelfClientProvider;
+ private readonly IAElfAccountProvider _aelfAccountProvider;
+ private readonly IObjectMapper _objectMapper;
+ private readonly AElfClientConfigOptions _clientConfigOptions;
+
+ public ILogger Logger { get; set; }
+
+ public AElfClientService(IAElfClientProvider aelfClientProvider, IAElfAccountProvider aelfAccountProvider,
+ IObjectMapper objectMapper, IOptionsSnapshot clientConfigOptions)
+ {
+ _aelfClientProvider = aelfClientProvider;
+ _aelfAccountProvider = aelfAccountProvider;
+ _objectMapper = objectMapper;
+ _clientConfigOptions = clientConfigOptions.Value;
+
+ Logger = NullLogger.Instance;
+ }
+
+ public async Task ViewAsync(string contractAddress, string methodName, IMessage parameter, string clientAlias,
+ string accountAlias = "Default") where T : IMessage, new()
+ {
+ var aelfClient = _aelfClientProvider.GetClient(alias: clientAlias);
+ var aelfAccount = _aelfAccountProvider.GetPrivateKey(alias: accountAlias);
+ var tx = new TransactionBuilder(aelfClient)
+ .UsePrivateKey(aelfAccount)
+ .UseContract(contractAddress)
+ .UseMethod(methodName)
+ .UseParameter(parameter)
+ .Build();
+ var returnValue = await PerformViewAsync(aelfClient, tx);
+ var result = new T();
+ result.MergeFrom(returnValue);
+ return result;
+ }
+
+
+ public async Task ViewSystemAsync(string systemContractName, string methodName, IMessage parameter,
+ string clientAlias, string accountAlias = "Default") where T : IMessage, new()
+ {
+ if (!systemContractName.StartsWith("AElf.ContractNames."))
+ {
+ throw new ArgumentException("Invalid system contract name.");
+ }
+
+ var aelfClient = _aelfClientProvider.GetClient(alias: clientAlias);
+ var aelfAccount = _aelfAccountProvider.GetPrivateKey(alias: accountAlias);
+ var tx = new TransactionBuilder(aelfClient)
+ .UsePrivateKey(aelfAccount)
+ .UseSystemContract(systemContractName)
+ .UseMethod(methodName)
+ .UseParameter(parameter)
+ .Build();
+ var returnValue = await PerformViewAsync(aelfClient, tx);
+ var result = new T();
+ result.MergeFrom(returnValue);
+ return result;
+ }
+
+ public async Task GetGenesisContractAddressAsync(string clientAlias)
+ {
+ var chainStatus = await GetChainStatusAsync(clientAlias);
+ return Address.FromBase58(chainStatus.GenesisContractAddress);
+ }
+
+ private async Task PerformViewAsync(ITransactionAppService aelfClient, Transaction tx)
+ {
+ var result = await aelfClient.ExecuteTransactionAsync(new ExecuteTransactionDto
+ {
+ RawTransaction = tx.ToByteArray().ToHex()
+ });
+ return ByteArrayHelper.HexStringToByteArray(result);
+ }
+}
\ No newline at end of file
diff --git a/src/AElf.Client.Core/ContractServiceBase.cs b/src/AElf.Client.Core/ContractServiceBase.cs
new file mode 100644
index 0000000..2f1901d
--- /dev/null
+++ b/src/AElf.Client.Core/ContractServiceBase.cs
@@ -0,0 +1,61 @@
+using Google.Protobuf;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
+using Volo.Abp.Threading;
+
+namespace AElf.Client.Core;
+
+public class ContractServiceBase
+{
+ private readonly IAElfClientService _clientService;
+ protected string? SmartContractName { get; }
+ protected Address? ContractAddress { get; set; }
+
+ public ILogger Logger { get; set; }
+
+ protected ContractServiceBase(IAElfClientService clientService, string smartContractName)
+ {
+ _clientService = clientService;
+ SmartContractName = smartContractName;
+
+ Logger = NullLogger.Instance;
+ }
+
+ protected ContractServiceBase(IAElfClientService clientService, Address contractAddress)
+ {
+ _clientService = clientService;
+ ContractAddress = contractAddress;
+
+ Logger = NullLogger.Instance;
+ }
+
+ protected async Task PerformSendTransactionAsync(string methodName, IMessage parameter,
+ string clientAlias)
+ {
+ if (ContractAddress != null)
+ {
+ return await _clientService.SendAsync(ContractAddress.ToBase58(), methodName, parameter, clientAlias);
+ }
+
+ if (SmartContractName != null)
+ {
+ return await _clientService.SendSystemAsync(SmartContractName, methodName, parameter, clientAlias);
+ }
+
+ Logger.LogError($"Neither ContractAddress nor SmartContractName is set.");
+ return null;
+ }
+
+ protected async Task PerformGetTransactionResultAsync(string transactionId,
+ string clientAlias)
+ {
+ TransactionResult txResult;
+ do
+ {
+ txResult = await _clientService.GetTransactionResultAsync(transactionId, clientAlias);
+ } while (txResult.Status == TransactionResultStatus.Pending);
+
+ Logger.LogInformation("{TxResult}", txResult);
+ return txResult;
+ }
+}
\ No newline at end of file
diff --git a/src/AElf.Client.Abp/GlobalUsings.cs b/src/AElf.Client.Core/GlobalUsings.cs
similarity index 100%
rename from src/AElf.Client.Abp/GlobalUsings.cs
rename to src/AElf.Client.Core/GlobalUsings.cs
diff --git a/src/AElf.Client.Abp/IAElfAccountProvider.cs b/src/AElf.Client.Core/IAElfAccountProvider.cs
similarity index 55%
rename from src/AElf.Client.Abp/IAElfAccountProvider.cs
rename to src/AElf.Client.Core/IAElfAccountProvider.cs
index f3a1809..74d02cc 100644
--- a/src/AElf.Client.Abp/IAElfAccountProvider.cs
+++ b/src/AElf.Client.Core/IAElfAccountProvider.cs
@@ -1,5 +1,5 @@
-using AElf.Client.Abp.Infrastructure;
-using AElf.Client.Options;
+using AElf.Client.Core.Infrastructure;
+using AElf.Client.Core.Options;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
@@ -7,17 +7,23 @@
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
-namespace AElf.Client.Abp;
+namespace AElf.Client.Core;
public interface IAElfAccountProvider
{
byte[] GetPrivateKey(string? alias = null, string? address = null);
- void SetPrivateKey(byte[] privateKey, string? alias = null, string? address = null);
+ void SetPrivateKey(byte[] privateKey, string? accountAlias = null);
+ void SetPrivateKey(string address, string password, string? accountAlias = null);
+ string GetAliasByAddress(string address);
+ void AddAccountByDefaultPassword(string address);
}
public class AElfAccountProvider : Dictionary, IAElfAccountProvider, ISingletonDependency
{
private readonly IKeyDirectoryProvider _keyDirectoryProvider;
+ private readonly AElfAccountOptions _aelfAccountOptions;
+
+ private readonly KeyStoreService _keyStoreService;
public ILogger Logger { get; set; }
@@ -26,10 +32,10 @@ public AElfAccountProvider(IKeyDirectoryProvider keyDirectoryProvider,
{
Logger = NullLogger.Instance;
_keyDirectoryProvider = keyDirectoryProvider;
+ _aelfAccountOptions = aelfAccountOptions.Value;
var defaultPrivateKey = ByteArrayHelper.HexStringToByteArray(AElfClientConstants.DefaultPrivateKey);
- SetPrivateKey(defaultPrivateKey, "Default", Address.FromPublicKey(defaultPrivateKey).ToBase58());
-
- var keyStoreService = new KeyStoreService();
+ SetPrivateKey(defaultPrivateKey, "Default");
+ _keyStoreService = new KeyStoreService();
foreach (var accountConfig in aelfAccountOptions.Value.AccountConfigList)
{
@@ -40,14 +46,14 @@ public AElfAccountProvider(IKeyDirectoryProvider keyDirectoryProvider,
{
using var textReader = File.OpenText(keyFilePath);
var json = textReader.ReadToEnd();
- return keyStoreService.DecryptKeyStoreFromJson(accountConfig.Password, json);
+ return _keyStoreService.DecryptKeyStoreFromJson(accountConfig.Password, json);
}));
- SetPrivateKey(privateKey, accountConfig.Alias, accountConfig.Address);
+ SetPrivateKey(privateKey, accountConfig.Alias);
}
else
{
var privateKey = ByteArrayHelper.HexStringToByteArray(accountConfig.PrivateKey);
- SetPrivateKey(privateKey, accountConfig.Alias, Address.FromPublicKey(privateKey).ToBase58());
+ SetPrivateKey(privateKey, accountConfig.Alias);
}
}
}
@@ -66,15 +72,56 @@ public byte[] GetPrivateKey(string? alias = null, string? address = null)
return this[keys.Single()];
}
- public void SetPrivateKey(byte[] privateKey, string? alias = null, string? address = null)
+ public void SetPrivateKey(byte[] privateKey, string? accountAlias = null)
{
TryAdd(new AElfAccountInfo
{
- Alias = alias,
+ Alias = accountAlias,
+ Address = Address.FromPublicKey(privateKey).ToBase58()
+ }, privateKey);
+ }
+
+ public void SetPrivateKey(string address, string password, string? accountAlias = null)
+ {
+ var keyFilePath = GetKeyFileFullPath(address, _aelfAccountOptions.KeyDirectory);
+ var privateKey = AsyncHelper.RunSync(() => Task.Run(() =>
+ {
+ using var textReader = File.OpenText(keyFilePath);
+ var json = textReader.ReadToEnd();
+ return _keyStoreService.DecryptKeyStoreFromJson(password, json);
+ }));
+
+ var keys = Keys
+ .WhereIf(!accountAlias.IsNullOrWhiteSpace(), a => a.Alias == accountAlias)
+ .WhereIf(!address.IsNullOrWhiteSpace(), a => a.Address == address)
+ .ToList();
+
+ if (keys.Count == 1) return;
+ TryAdd(new AElfAccountInfo
+ {
+ Alias = accountAlias,
Address = address
}, privateKey);
}
+ public string GetAliasByAddress(string address)
+ {
+ var keys = Keys
+ .WhereIf(!address.IsNullOrWhiteSpace(), a => a.Address == address)
+ .ToList();
+ if (keys.Count != 1)
+ {
+ throw new AElfClientException($"Failed to get alias of {address}.");
+ }
+
+ return keys.First().Alias!;
+ }
+
+ public void AddAccountByDefaultPassword(string address)
+ {
+ SetPrivateKey(address, _aelfAccountOptions.DefaultPassword);
+ }
+
private string GetKeyFileFullPath(string address, string configuredKeyDirectory)
{
var dirPath = GetKeystoreDirectoryPath(configuredKeyDirectory);
diff --git a/src/AElf.Client.Abp/IAElfClientProvider.cs b/src/AElf.Client.Core/IAElfClientProvider.cs
similarity index 73%
rename from src/AElf.Client.Abp/IAElfClientProvider.cs
rename to src/AElf.Client.Core/IAElfClientProvider.cs
index d138778..a0f1794 100644
--- a/src/AElf.Client.Abp/IAElfClientProvider.cs
+++ b/src/AElf.Client.Core/IAElfClientProvider.cs
@@ -1,8 +1,8 @@
-using AElf.Client.Options;
+using AElf.Client.Core.Options;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
-namespace AElf.Client;
+namespace AElf.Client.Core;
public interface IAElfClientProvider
{
@@ -14,19 +14,21 @@ void SetClient(AElfClient client, string? environment = null, int? chainId = nul
public class AElfClientProvider : Dictionary, IAElfClientProvider, ISingletonDependency
{
- public AElfClientProvider(IOptionsSnapshot aelfClientOptions)
+ public AElfClientProvider(IOptionsSnapshot aelfClientOptions,
+ IOptionsSnapshot aelfClientConfigOptions)
{
+ var useCamelCase = aelfClientConfigOptions.Value.CamelCase;
var clientBuilder = new AElfClientBuilder();
- SetClient(clientBuilder.UsePublicEndpoint(EndpointType.MainNetMainChain).Build(), "MainNet",
- AElfClientConstants.MainChainId, "MainChain", EndpointType.MainNetMainChain.ToString());
- SetClient(clientBuilder.UsePublicEndpoint(EndpointType.MainNetSidechain).Build(), "MainNet",
- AElfClientConstants.SidechainId, "Sidechain", EndpointType.MainNetSidechain.ToString());
- SetClient(clientBuilder.UsePublicEndpoint(EndpointType.TestNetMainChain).Build(), "TestNet",
- AElfClientConstants.MainChainId, "MainChain", EndpointType.TestNetMainChain.ToString());
- SetClient(clientBuilder.UsePublicEndpoint(EndpointType.TestNetSidechain).Build(), "MainNet",
- AElfClientConstants.SidechainId, "Sidechain", EndpointType.TestNetSidechain.ToString());
- SetClient(clientBuilder.UsePublicEndpoint(EndpointType.Local).Build(), "Local", AElfClientConstants.MainChainId,
- "MainChain", EndpointType.Local.ToString());
+ SetClient(clientBuilder.UsePublicEndpoint(EndpointType.MainNetMainChain).UseCamelCase(useCamelCase).Build(),
+ "MainNet", AElfClientConstants.MainChainId, "MainChain", EndpointType.MainNetMainChain.ToString());
+ SetClient(clientBuilder.UsePublicEndpoint(EndpointType.MainNetSideChain1).UseCamelCase(useCamelCase).Build(),
+ "MainNet", AElfClientConstants.SideChainId2, "SideChain", EndpointType.MainNetSideChain1.ToString());
+ SetClient(clientBuilder.UsePublicEndpoint(EndpointType.TestNetMainChain).UseCamelCase(useCamelCase).Build(),
+ "TestNet", AElfClientConstants.MainChainId, "MainChain", EndpointType.TestNetMainChain.ToString());
+ SetClient(clientBuilder.UsePublicEndpoint(EndpointType.TestNetSideChain2).UseCamelCase(useCamelCase).Build(),
+ "MainNet", AElfClientConstants.SideChainId2, "SideChain", EndpointType.TestNetSideChain2.ToString());
+ SetClient(clientBuilder.UsePublicEndpoint(EndpointType.Local).UseCamelCase(useCamelCase).Build(), "Local",
+ AElfClientConstants.MainChainId, "MainChain", EndpointType.Local.ToString());
foreach (var clientConfig in aelfClientOptions.Value.ClientConfigList)
{
diff --git a/src/AElf.Client.Core/IAElfClientService.cs b/src/AElf.Client.Core/IAElfClientService.cs
new file mode 100644
index 0000000..980bee3
--- /dev/null
+++ b/src/AElf.Client.Core/IAElfClientService.cs
@@ -0,0 +1,72 @@
+using AElf.Client.Dto;
+using Google.Protobuf;
+using Google.Protobuf.Reflection;
+
+namespace AElf.Client.Core;
+
+public interface IAElfClientService
+{
+ ///
+ /// Build a transaction to view contract state and return the result.
+ ///
+ /// Transaction.To
+ /// Transaction.MethodName
+ /// Transaction.Parameter
+ /// Which client to use
+ /// Which account to use
+ /// Only IMessage type
+ /// Contract call result
+ Task ViewAsync(string contractAddress, string methodName, IMessage parameter, string clientAlias,
+ string accountAlias = "Default") where T : IMessage, new();
+
+ ///
+ /// Build a transaction to view system contract state and return the result.
+ ///
+ /// The System Contract Name with the format AElf.ContractNames.*
+ /// Transaction.MethodName
+ /// Transaction.Parameter
+ /// Which client to use
+ /// Which account to use
+ /// Only IMessage type
+ /// Contract call result
+ /// Throw Invalid system contract name
if systemContractName
+ /// is not starts with AElf.ContractNames.
+ Task ViewSystemAsync(string systemContractName, string methodName, IMessage parameter,
+ string clientAlias, string accountAlias = "Default") where T : IMessage, new();
+
+ ///
+ /// Send a transaction to a Contract.
+ ///
+ /// Transaction.tO
+ /// Transaction.MethodName
+ /// Transaction.Parameter
+ /// Which client to use
+ /// Which account to use
+ /// Contract call result
+ Task SendAsync(string contractAddress, string methodName, IMessage parameter,
+ string clientAlias, string? accountAlias = null);
+
+ ///
+ /// Send a transaction to a System Contract.
+ ///
+ /// The System Contract Name with the format AElf.ContractNames.*
+ /// Transaction.MethodName
+ /// Transaction.Parameter
+ /// Which client to use
+ /// Which account to use
+ /// Contract call result
+ /// Throw Invalid system contract name
if systemContractName
+ /// is not starts with AElf.ContractNames.
+ Task SendSystemAsync(string systemContractName, string methodName, IMessage parameter,
+ string clientAlias, string? accountAlias = null);
+
+ Task GetTransactionResultAsync(string transactionId, string clientAlias);
+
+ Task GetChainStatusAsync(string clientAlias);
+
+ Task GetGenesisContractAddressAsync(string clientAlias);
+
+ Task GetMerklePathByTransactionIdAsync(string transactionId, string clientAlias);
+
+ Task GetContractFileDescriptorSetAsync(string contractAddress, string clientAlias);
+}
\ No newline at end of file
diff --git a/src/AElf.Client.Abp/Infrastructure/IKeyDirectoryProvider.cs b/src/AElf.Client.Core/Infrastructure/IKeyDirectoryProvider.cs
similarity index 62%
rename from src/AElf.Client.Abp/Infrastructure/IKeyDirectoryProvider.cs
rename to src/AElf.Client.Core/Infrastructure/IKeyDirectoryProvider.cs
index a89a5ee..77ef341 100644
--- a/src/AElf.Client.Abp/Infrastructure/IKeyDirectoryProvider.cs
+++ b/src/AElf.Client.Core/Infrastructure/IKeyDirectoryProvider.cs
@@ -1,4 +1,4 @@
-namespace AElf.Client.Abp.Infrastructure;
+namespace AElf.Client.Core.Infrastructure;
public interface IKeyDirectoryProvider
{
diff --git a/src/AElf.Client.Abp/Infrastructure/KeyDirectoryProvider.cs b/src/AElf.Client.Core/Infrastructure/KeyDirectoryProvider.cs
similarity index 93%
rename from src/AElf.Client.Abp/Infrastructure/KeyDirectoryProvider.cs
rename to src/AElf.Client.Core/Infrastructure/KeyDirectoryProvider.cs
index 99dd09b..789672b 100644
--- a/src/AElf.Client.Abp/Infrastructure/KeyDirectoryProvider.cs
+++ b/src/AElf.Client.Core/Infrastructure/KeyDirectoryProvider.cs
@@ -1,6 +1,6 @@
using Volo.Abp.DependencyInjection;
-namespace AElf.Client.Abp.Infrastructure;
+namespace AElf.Client.Core.Infrastructure;
public class KeyDirectoryProvider : IKeyDirectoryProvider, ISingletonDependency
{
diff --git a/src/AElf.Client.Abp/Options/AElfAccountOptions.cs b/src/AElf.Client.Core/Options/AElfAccountOptions.cs
similarity index 80%
rename from src/AElf.Client.Abp/Options/AElfAccountOptions.cs
rename to src/AElf.Client.Core/Options/AElfAccountOptions.cs
index 310f2f5..2df14ba 100644
--- a/src/AElf.Client.Abp/Options/AElfAccountOptions.cs
+++ b/src/AElf.Client.Core/Options/AElfAccountOptions.cs
@@ -1,9 +1,10 @@
-namespace AElf.Client.Options;
+namespace AElf.Client.Core.Options;
public class AElfAccountOptions
{
public string KeyDirectory { get; set; }
public List AccountConfigList { get; set; } = new();
+ public string DefaultPassword { get; set; }
}
public class AccountConfig
diff --git a/src/AElf.Client.Core/Options/AElfClientConfigOptions.cs b/src/AElf.Client.Core/Options/AElfClientConfigOptions.cs
new file mode 100644
index 0000000..816a4ef
--- /dev/null
+++ b/src/AElf.Client.Core/Options/AElfClientConfigOptions.cs
@@ -0,0 +1,10 @@
+namespace AElf.Client.Core.Options;
+
+public class AElfClientConfigOptions
+{
+ public string ClientAlias { get; set; } = "TestNetSideChain2";
+ public string MainChainClientAlias { get; set; } = "TestNetMainChain";
+ public string SideChainClientAlias { get; set; } = "TestNetSideChain2";
+ public string AccountAlias { get; set; } = "Default";
+ public bool CamelCase { get; set; } = false;
+}
\ No newline at end of file
diff --git a/src/AElf.Client.Abp/Options/AElfClientOptions.cs b/src/AElf.Client.Core/Options/AElfClientOptions.cs
similarity index 68%
rename from src/AElf.Client.Abp/Options/AElfClientOptions.cs
rename to src/AElf.Client.Core/Options/AElfClientOptions.cs
index 1caf518..ae612dd 100644
--- a/src/AElf.Client.Abp/Options/AElfClientOptions.cs
+++ b/src/AElf.Client.Core/Options/AElfClientOptions.cs
@@ -1,4 +1,4 @@
-namespace AElf.Client.Options;
+namespace AElf.Client.Core.Options;
public class AElfClientOptions
{
@@ -9,7 +9,7 @@ public class ClientConfig
{
public string Alias { get; set; }
public string Endpoint { get; set; }
- public string UserName { get; set; }
- public string Password { get; set; }
+ public string? UserName { get; set; }
+ public string? Password { get; set; }
public int Timeout { get; set; } = 60;
}
\ No newline at end of file
diff --git a/src/AElf.Client.Core/Options/AElfContractOptions.cs b/src/AElf.Client.Core/Options/AElfContractOptions.cs
new file mode 100644
index 0000000..25f3e7a
--- /dev/null
+++ b/src/AElf.Client.Core/Options/AElfContractOptions.cs
@@ -0,0 +1,7 @@
+namespace AElf.Client.Core.Options;
+
+public class AElfContractOptions
+{
+ public Dictionary ContractAddressList { get; set; }
+ public string ContractDirectory { get; set; }
+}
\ No newline at end of file
diff --git a/src/AElf.Client.Core/Profile/CommonProfile.cs b/src/AElf.Client.Core/Profile/CommonProfile.cs
new file mode 100644
index 0000000..3bacaa9
--- /dev/null
+++ b/src/AElf.Client.Core/Profile/CommonProfile.cs
@@ -0,0 +1,27 @@
+using Google.Protobuf;
+
+namespace AElf.Client.Core;
+
+public class CommonProfile : AutoMapper.Profile
+{
+ public CommonProfile()
+ {
+ CreateMap()
+ .ConvertUsing(s => s == null ? null : s.ToHex());
+
+ CreateMap()
+ .ConvertUsing(s => Hash.LoadFromHex(s));
+
+ CreateMap()
+ .ConvertUsing(s => s.ToBase58());
+
+ CreateMap()
+ .ConvertUsing(s => Address.FromBase58(s));
+
+ CreateMap()
+ .ConvertUsing(s => s.ToBase64());
+
+ CreateMap()
+ .ConvertUsing(s => ByteString.CopyFromUtf8(s));
+ }
+}
\ No newline at end of file
diff --git a/src/AElf.Client.Core/Profile/MerklePathProfile.cs b/src/AElf.Client.Core/Profile/MerklePathProfile.cs
new file mode 100644
index 0000000..8a9bf65
--- /dev/null
+++ b/src/AElf.Client.Core/Profile/MerklePathProfile.cs
@@ -0,0 +1,16 @@
+using AElf.Client.Dto;
+using AutoMapper;
+
+namespace AElf.Client.Core;
+
+public class MerklePathProfile : Profile
+{
+ public MerklePathProfile()
+ {
+ CreateMap();
+ CreateMap();
+
+ CreateMap();
+ CreateMap();
+ }
+}
\ No newline at end of file
diff --git a/src/AElf.Client.Core/Profile/TransactionProfile.cs b/src/AElf.Client.Core/Profile/TransactionProfile.cs
new file mode 100644
index 0000000..f776623
--- /dev/null
+++ b/src/AElf.Client.Core/Profile/TransactionProfile.cs
@@ -0,0 +1,78 @@
+using AElf.Client.Dto;
+using AutoMapper;
+using Google.Protobuf;
+using Volo.Abp.AutoMapper;
+
+namespace AElf.Client.Core;
+
+public class TransactionProfile : Profile
+{
+ public const string ErrorTrace = "WithMetrics";
+
+ public TransactionProfile()
+ {
+ CreateMap();
+ CreateMap();
+
+ CreateMap()
+ .ForMember(d => d.ReturnValue, opt => opt.MapFrom(s => s.ReturnValue.ToHex(false)))
+ .ForMember(d => d.Bloom,
+ opt => opt.MapFrom(s =>
+ s.Status == TransactionResultStatus.NotExisted
+ ? null
+ : s.Bloom.Length == 0
+ ? ByteString.CopyFrom(new byte[256]).ToBase64()
+ : s.Bloom.ToBase64()))
+ .ForMember(d => d.Status, opt => opt.MapFrom(s => s.Status.ToString().ToUpper()))
+ .ForMember(d => d.Error, opt => opt.MapFrom())
+ .Ignore(d => d.Transaction)
+ .Ignore(d => d.TransactionSize);
+
+ TransactionResultStatus status;
+ CreateMap()
+ .ForMember(d => d.ReturnValue,
+ opt => opt.MapFrom(s => ByteString.CopyFrom(ByteArrayHelper.HexStringToByteArray(s.ReturnValue))))
+ .ForMember(d => d.BlockHash, opt => opt.MapFrom(s => Hash.LoadFromHex(s.BlockHash)))
+ .ForMember(d => d.Bloom, opt => opt.MapFrom(s =>
+ s.Status.ToUpper() == TransactionResultStatus.NotExisted.ToString().ToUpper()
+ ? null
+ : string.IsNullOrEmpty(s.Bloom)
+ ? ByteString.Empty
+ : ByteString.FromBase64(s.Bloom)))
+ .ForMember(d => d.Status,
+ opt => opt.MapFrom(s =>
+ Enum.TryParse($"{s.Status[0]}{s.Status.Substring(1).ToLower()}", out status)
+ ? status
+ : TransactionResultStatus.NotExisted))
+ .ForMember(d => d.Logs, opt => opt.MapFrom(s => s.Logs))
+ .Ignore(d => d.Error)
+ .Ignore(d => d.Bloom);
+
+ CreateMap()
+ .ForMember(d => d.Indexed, opt => opt.MapFrom(s => s.Indexed.Select(ByteString.FromBase64)))
+ .ForMember(d => d.NonIndexed, opt => opt.MapFrom(s => ByteString.FromBase64(s.NonIndexed)));
+ CreateMap();
+ }
+}
+
+public class TransactionErrorResolver : IValueResolver
+{
+ public string Resolve(TransactionResult source, TransactionResultDto destination, string destMember,
+ ResolutionContext context)
+ {
+ var errorTraceNeeded = (bool)context.Items[TransactionProfile.ErrorTrace];
+ return TakeErrorMessage(source.Error, errorTraceNeeded);
+ }
+
+ public static string TakeErrorMessage(string transactionResultError, bool errorTraceNeeded)
+ {
+ if (string.IsNullOrWhiteSpace(transactionResultError))
+ return null;
+
+ if (errorTraceNeeded)
+ return transactionResultError;
+
+ using var stringReader = new StringReader(transactionResultError);
+ return stringReader.ReadLine();
+ }
+}
\ No newline at end of file
diff --git a/src/AElf.Client.Core/SendTransactionResult.cs b/src/AElf.Client.Core/SendTransactionResult.cs
new file mode 100644
index 0000000..057d94e
--- /dev/null
+++ b/src/AElf.Client.Core/SendTransactionResult.cs
@@ -0,0 +1,7 @@
+namespace AElf.Client.Core;
+
+public class SendTransactionResult
+{
+ public TransactionResult TransactionResult { get; set; }
+ public Transaction Transaction { get; set; }
+}
\ No newline at end of file
diff --git a/src/AElf.Client.Protobuf/AElf.Client.Protobuf.csproj b/src/AElf.Client.Protobuf/AElf.Client.Protobuf.csproj
index a582f80..c9b869f 100644
--- a/src/AElf.Client.Protobuf/AElf.Client.Protobuf.csproj
+++ b/src/AElf.Client.Protobuf/AElf.Client.Protobuf.csproj
@@ -26,21 +26,57 @@
MSBuild:Compile
+
+ MSBuild:Compile
+
MSBuild:Compile
MSBuild:Compile
+
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+
MSBuild:Compile
+
+ MSBuild:Compile
+
MSBuild:Compile
MSBuild:Compile
+
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+
+
+ MSBuild:Compile
+
diff --git a/src/AElf.Client.Protobuf/Protobuf/acs13.proto b/src/AElf.Client.Protobuf/Protobuf/acs13.proto
new file mode 100644
index 0000000..2f80e12
--- /dev/null
+++ b/src/AElf.Client.Protobuf/Protobuf/acs13.proto
@@ -0,0 +1,21 @@
+syntax = "proto3";
+
+package acs13;
+import "aelf/options.proto";
+import "aelf/core.proto";
+import "google/protobuf/wrappers.proto";
+
+option (aelf.identity) = "acs13";
+option csharp_namespace = "AElf.Standards.ACS13";
+
+service OracleAggregatorContract {
+ rpc Aggregate (AggregateInput) returns (google.protobuf.StringValue) {
+ }
+}
+
+
+message AggregateInput {
+ repeated string results = 1;
+ repeated int32 frequencies = 2;
+ int32 aggregate_option = 3;
+}
\ No newline at end of file
diff --git a/src/AElf.Client.Protobuf/Protobuf/bridge_contract.proto b/src/AElf.Client.Protobuf/Protobuf/bridge_contract.proto
new file mode 100644
index 0000000..47e8672
--- /dev/null
+++ b/src/AElf.Client.Protobuf/Protobuf/bridge_contract.proto
@@ -0,0 +1,207 @@
+syntax = "proto3";
+
+import "aelf/core.proto";
+import "aelf/options.proto";
+import "google/protobuf/empty.proto";
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/wrappers.proto";
+import "callback_input.proto";
+import "acs13.proto";
+import "receipt_maker.proto";
+
+option csharp_namespace = "AElf.Contracts.Bridge";
+
+service BridgeContract {
+ option (aelf.csharp_state) = "AElf.Contracts.Bridge.BridgeContractState";
+ option (aelf.base) = "acs13.proto";
+ option (aelf.base) = "receipt_maker.proto";
+
+ rpc Initialize (InitializeInput) returns (google.protobuf.Empty) {}
+
+ rpc CreateSwap (CreateSwapInput) returns (aelf.Hash) {
+ }
+ rpc SwapToken (SwapTokenInput) returns (google.protobuf.Empty) {
+ }
+ rpc ChangeSwapRatio (ChangeSwapRatioInput) returns (google.protobuf.Empty) {
+ }
+ rpc Deposit (DepositInput) returns (google.protobuf.Empty) {
+ }
+ rpc Withdraw (WithdrawInput) returns (google.protobuf.Empty) {
+ }
+ rpc UpdateMerkleTree (UpdateMerkleTreeInput) returns (google.protobuf.Empty) {
+ }
+ rpc RecordReceiptHash (CallbackInput) returns (google.protobuf.Empty) {
+ }
+
+ rpc ChangeMaximalLeafCount (google.protobuf.Int32Value) returns (google.protobuf.Empty) {
+ }
+
+ // view methods
+
+ rpc GetSwapInfo (aelf.Hash) returns (SwapInfo) {
+ option (aelf.is_view) = true;
+ }
+ rpc GetSwapPair (GetSwapPairInput) returns (SwapPair) {
+ option (aelf.is_view) = true;
+ }
+ rpc GetSwapAmounts (GetSwapAmountsInput) returns (SwapAmounts) {
+ option (aelf.is_view) = true;
+ }
+ rpc GetRegimentAddressByRecorderId (google.protobuf.Int64Value) returns (aelf.Address) {
+ option (aelf.is_view) = true;
+ }
+ rpc GetSwappedReceiptIdList (GetSwappedReceiptIdListInput) returns (ReceiptIdList) {
+ option (aelf.is_view) = true;
+ }
+ rpc GetSwappedReceiptInfoList (GetSwappedReceiptInfoListInput) returns (ReceiptInfoList) {
+ option (aelf.is_view) = true;
+ }
+}
+
+message InitializeInput {
+ aelf.Address oracle_contract_address = 1;
+ aelf.Address merkle_tree_recorder_contract_address = 2;
+ aelf.Address regiment_contract_address = 3;
+ aelf.Address merkle_tree_generator_contract_address = 4;
+ int32 merkle_tree_leaf_limit = 5;
+}
+
+message CreateSwapInput {
+ int32 origin_token_size_in_byte = 1;
+ bool origin_token_numeric_big_endian = 2;
+ repeated SwapTargetToken swap_target_token_list = 3;
+ aelf.Address regiment_address = 4;
+}
+
+message SwapTargetToken {
+ string target_token_symbol = 1;
+ SwapRatio swap_ratio = 2;
+ int64 deposit_amount = 3;
+}
+
+message SwapInfo {
+ aelf.Hash swap_id = 1;
+ int32 origin_token_size_in_byte = 2;
+ bool origin_token_numeric_big_endian = 3;
+ map swap_target_token_map = 4;
+ aelf.Address regiment_address = 5;
+ int64 recorder_id = 6;
+}
+
+message SwapPair {
+ aelf.Hash swap_id = 1;
+ int32 origin_token_size_in_byte = 2;
+ bool origin_token_numeric_big_endian = 3;
+ string target_token_symbol = 4;
+ SwapRatio swap_ratio = 5;
+ int64 swapped_amount = 6;
+ int64 swapped_times = 7;
+ int64 deposit_amount = 8;
+}
+
+message SwapRatio {
+ int64 origin_share = 1;
+ int64 target_share = 2;
+}
+
+message ChangeSwapRatioInput {
+ aelf.Hash swap_id = 1;
+ SwapRatio swap_ratio = 2;
+ string target_token_symbol = 3;
+}
+
+message SwapTokenInput {
+ aelf.Hash swap_id = 1;
+ int64 receipt_id = 2;
+ string origin_amount = 3;
+}
+
+message DepositInput {
+ aelf.Hash swap_id = 1;
+ string target_token_symbol = 2;
+ int64 amount = 3;
+}
+
+message GetSwapPairInput {
+ aelf.Hash swap_id = 1;
+ string target_token_symbol = 2;
+}
+
+message GetSwapAmountsInput {
+ aelf.Hash swap_id = 1;
+ int64 receipt_id = 2;
+}
+
+message SwapAmounts {
+ aelf.Address receiver = 1;
+ map received_amounts = 2;
+}
+
+message WithdrawInput {
+ aelf.Hash swap_id = 1;
+ string target_token_symbol = 2;
+ int64 amount = 3;
+}
+
+message ReceiptHashMap {
+ map value = 1;
+ int64 recorder_id = 2;
+}
+
+message UpdateMerkleTreeInput {
+ int64 recorder_id = 1;
+ aelf.Address regiment_address = 2;
+}
+
+message ReceiptIdList {
+ repeated int64 value = 1;
+}
+
+message GetSwappedReceiptIdListInput {
+ aelf.Hash swap_id = 1;
+ aelf.Address receiver_address = 2;
+}
+
+message GetSwappedReceiptInfoListInput {
+ aelf.Hash swap_id = 1;
+ aelf.Address receiving_address = 2;
+}
+
+message ReceiptInfo {
+ int64 receipt_id = 1;
+ aelf.Hash receiving_tx_id = 2;
+ google.protobuf.Timestamp receiving_time = 3;
+ int64 amount = 4;
+ map amount_map = 5;
+}
+
+message ReceiptInfoList {
+ repeated ReceiptInfo value = 1;
+}
+
+message SendingInfo {
+ int64 receipt_id = 1;
+ string sending_tx_id = 2;
+ string sending_time = 3;
+}
+
+// Events
+
+message SwapRatioChanged {
+ option (aelf.is_event) = true;
+ aelf.Hash swap_id = 1;
+ SwapRatio new_swap_ratio = 2;
+ string target_token_symbol = 3;
+}
+
+message TokenSwapped {
+ option (aelf.is_event) = true;
+ aelf.Address address = 1;
+ int64 amount = 2;
+ string symbol = 3;
+}
+
+message SwapPairAdded {
+ option (aelf.is_event) = true;
+ aelf.Hash swap_id = 1;
+}
\ No newline at end of file
diff --git a/src/AElf.Client.Protobuf/Protobuf/callback_input.proto b/src/AElf.Client.Protobuf/Protobuf/callback_input.proto
new file mode 100644
index 0000000..c389829
--- /dev/null
+++ b/src/AElf.Client.Protobuf/Protobuf/callback_input.proto
@@ -0,0 +1,9 @@
+syntax = "proto3";
+
+import "aelf/core.proto";
+
+message CallbackInput {
+ aelf.Hash query_id = 1;
+ bytes result = 2;
+ repeated aelf.Address oracle_nodes = 3;
+}
\ No newline at end of file
diff --git a/src/AElf.Client.Protobuf/Protobuf/nft_contract.proto b/src/AElf.Client.Protobuf/Protobuf/nft_contract.proto
new file mode 100644
index 0000000..b3521f6
--- /dev/null
+++ b/src/AElf.Client.Protobuf/Protobuf/nft_contract.proto
@@ -0,0 +1,505 @@
+/**
+ * NFT contract.
+ */
+syntax = "proto3";
+
+package nft;
+
+import "aelf/core.proto";
+import "aelf/options.proto";
+import "acs1.proto";
+import "transaction_fee.proto";
+import "authority_info.proto";
+import "google/protobuf/empty.proto";
+import "google/protobuf/wrappers.proto";
+
+option csharp_namespace = "AElf.Contracts.NFT";
+
+service NFTContract {
+ option (aelf.csharp_state) = "AElf.Contracts.NFT.NFTContractState";
+ option (aelf.base) = "acs1.proto";
+
+ // Create a new nft protocol.
+ rpc Create (CreateInput) returns (google.protobuf.StringValue) {
+ }
+ rpc CrossChainCreate (CrossChainCreateInput) returns (google.protobuf.Empty) {
+ }
+ // Mint (Issue) an amount of nft.
+ rpc Mint (MintInput) returns (aelf.Hash) {
+ }
+ // Transfer nft to another address.
+ rpc Transfer (TransferInput) returns (google.protobuf.Empty) {
+ }
+ // Transfer nft from one address to another.
+ rpc TransferFrom (TransferFromInput) returns (google.protobuf.Empty) {
+ }
+ // Approve another address to transfer nft from own account.
+ rpc Approve (ApproveInput) returns (google.protobuf.Empty) {
+ }
+ // De-approve.
+ rpc UnApprove (UnApproveInput) returns (google.protobuf.Empty) {
+ }
+ // Approve or de-approve another address as the operator of all NFTs of a certain protocol.
+ rpc ApproveProtocol (ApproveProtocolInput) returns (google.protobuf.Empty) {
+ }
+ // Destroy nfts.
+ rpc Burn (BurnInput) returns (google.protobuf.Empty) {
+ }
+ // Lock several nfts and fts to mint one nft.
+ rpc Assemble (AssembleInput) returns (aelf.Hash) {
+ }
+ // Disassemble one assembled nft to get locked nfts and fts back.
+ rpc Disassemble (DisassembleInput) returns (google.protobuf.Empty) {
+ }
+ // Modify metadata of one nft.
+ rpc Recast (RecastInput) returns (google.protobuf.Empty) {
+ }
+
+ rpc AddMinters (AddMintersInput) returns (google.protobuf.Empty) {
+ }
+ rpc RemoveMinters (RemoveMintersInput) returns (google.protobuf.Empty) {
+ }
+
+ rpc AddNFTType (AddNFTTypeInput) returns (google.protobuf.Empty) {
+ }
+ rpc RemoveNFTType (google.protobuf.StringValue) returns (google.protobuf.Empty) {
+ }
+
+ rpc GetNFTProtocolInfo (google.protobuf.StringValue) returns (NFTProtocolInfo) {
+ option (aelf.is_view) = true;
+ }
+ rpc GetNFTInfo (GetNFTInfoInput) returns (NFTInfo) {
+ option (aelf.is_view) = true;
+ }
+ rpc GetNFTInfoByTokenHash (aelf.Hash) returns (NFTInfo) {
+ option (aelf.is_view) = true;
+ }
+ rpc GetBalance (GetBalanceInput) returns (GetBalanceOutput) {
+ option (aelf.is_view) = true;
+ }
+ rpc GetBalanceByTokenHash (GetBalanceByTokenHashInput) returns (GetBalanceOutput) {
+ option (aelf.is_view) = true;
+ }
+ rpc GetAllowance (GetAllowanceInput) returns (GetAllowanceOutput) {
+ option (aelf.is_view) = true;
+ }
+ rpc GetAllowanceByTokenHash (GetAllowanceByTokenHashInput) returns (GetAllowanceOutput) {
+ option (aelf.is_view) = true;
+ }
+ rpc GetMinterList (google.protobuf.StringValue) returns (MinterList) {
+ option (aelf.is_view) = true;
+ }
+ rpc CalculateTokenHash (CalculateTokenHashInput) returns (aelf.Hash) {
+ option (aelf.is_view) = true;
+ }
+ rpc GetNFTTypes (google.protobuf.Empty) returns (NFTTypes) {
+ option (aelf.is_view) = true;
+ }
+ rpc GetOperatorList (GetOperatorListInput) returns (AddressList) {
+ option (aelf.is_view) = true;
+ }
+}
+
+// Structs
+message NFTTypes {
+ map value = 1;
+}
+
+// Inputs
+message CreateInput {
+ // The type of this nft protocol.
+ string nft_type = 1;
+ // The name of this nft protocol.
+ string protocol_name = 2;
+ // The total supply of the token.
+ int64 total_supply = 3;
+ // The address that created the token.
+ aelf.Address creator = 4;
+ // A flag indicating if this token is burnable.
+ bool is_burnable = 5;
+ // The chain id of the token.
+ int32 issue_chain_id = 6;
+ // The metadata of the token.
+ Metadata metadata = 7;
+ // Base Uri.
+ string base_uri = 8;
+ // Is token id can be reused.
+ bool is_token_id_reuse = 9;
+ // Initial minter list (creator will be added automatically)
+ MinterList minter_list = 10;
+}
+
+message CrossChainCreateInput {
+ string symbol = 1;
+}
+
+message TransferInput {
+ aelf.Address to = 1;
+ string symbol = 2;
+ int64 token_id = 3;
+ string memo = 4;
+ int64 amount = 5;
+}
+
+message TransferFromInput {
+ aelf.Address from = 1;
+ aelf.Address to = 2;
+ string symbol = 3;
+ int64 token_id = 4;
+ string memo = 5;
+ int64 amount = 6;
+}
+
+message ApproveInput {
+ aelf.Address spender = 1;
+ string symbol = 2;
+ int64 token_id = 3;
+ int64 amount = 4;
+}
+
+message UnApproveInput {
+ aelf.Address spender = 1;
+ string symbol = 2;
+ int64 token_id = 3;
+ int64 amount = 4;
+}
+
+message ApproveProtocolInput {
+ aelf.Address operator = 1;
+ string symbol = 2;
+ bool approved = 3;
+}
+
+message AddressList {
+ repeated aelf.Address value = 1;
+}
+
+message GetOperatorListInput {
+ string symbol = 1;
+ aelf.Address owner = 2;
+}
+
+message BurnInput {
+ string symbol = 1;
+ int64 token_id = 2;
+ int64 amount = 3;
+}
+
+message AssembleInput {
+ string symbol = 1;
+ aelf.Address owner = 2;
+ string uri = 3;
+ string alias = 4;
+ Metadata metadata = 5;
+ AssembledNfts assembled_nfts = 6;
+ AssembledFts assembled_fts = 7;
+ int64 token_id = 8;
+}
+
+message DisassembleInput {
+ string symbol = 1;
+ int64 token_id = 2;
+ aelf.Address owner = 3;
+}
+
+message MinterList {
+ repeated aelf.Address value = 1;
+}
+
+message MintInput {
+ string symbol = 1;
+ aelf.Address owner = 2;
+ string uri = 3;
+ string alias = 4;
+ Metadata metadata = 5;
+ int64 quantity = 6;
+ int64 token_id = 7;
+}
+
+message GetBalanceInput {
+ aelf.Address owner = 1;
+ string symbol = 2;
+ int64 token_id = 3;
+}
+
+message GetBalanceByTokenHashInput {
+ aelf.Address owner = 1;
+ aelf.Hash token_hash = 2;
+}
+
+message GetBalanceOutput {
+ aelf.Address owner = 1;
+ aelf.Hash token_hash = 2;
+ int64 balance = 3;
+}
+
+message GetAllowanceInput {
+ string symbol = 1;
+ int64 token_id = 2;
+ aelf.Address owner = 3;
+ aelf.Address spender = 4;
+}
+
+message GetAllowanceByTokenHashInput {
+ aelf.Hash token_hash = 1;
+ aelf.Address owner = 2;
+ aelf.Address spender = 3;
+}
+
+message GetAllowanceOutput {
+ aelf.Hash token_hash = 1;
+ int64 allowance = 2;
+ aelf.Address owner = 3;
+ aelf.Address spender = 4;
+}
+
+message CalculateTokenHashInput {
+ string symbol = 1;
+ int64 token_id = 2;
+}
+
+message NFTProtocolInfo {
+ // The symbol of the token.
+ string symbol = 1;
+ // The minted number of the token.
+ int64 supply = 2;
+ // The total number of the token.
+ int64 total_supply = 3;
+ // The address that creat the token.
+ aelf.Address creator = 4;
+ // Base Uri.
+ string base_uri = 5;
+ // A flag indicating if this token is burnable.
+ bool is_burnable = 6;
+ // The chain to mint this token.
+ int32 issue_chain_id = 7;
+ // The metadata of the token.
+ Metadata metadata = 8;
+ // NFT Type.
+ string nft_type = 9;
+ // Protocol name, aka token name in MultiToken Contract.
+ string protocol_name = 10;
+ // Is token id can be reused.
+ bool is_token_id_reuse = 11;
+ int64 issued = 12;
+}
+
+message NFTInfo {
+ // The symbol of the protocol this nft belongs to.
+ string symbol = 1;
+ // The name of the protocol this nft belongs to.
+ string protocol_name = 2;
+ // Actually is the order of this token.
+ int64 token_id = 3;
+ // The address that creat the base token.
+ aelf.Address creator = 4;
+ // The addresses that mint this token.
+ repeated aelf.Address minters = 5;
+ // The metadata of the token.
+ Metadata metadata = 6;
+ // Minted amount.
+ int64 quantity = 7;
+ // Token Uri.
+ string uri = 8;
+ // Base Uri.
+ string base_uri = 9;
+ // Alias
+ string alias = 10;
+ // Is burned.
+ bool is_burned = 11;
+ // NFT Type
+ string nft_type = 12;
+}
+
+enum NFTType {
+ ANY = 0;
+ ART = 1;
+ MUSIC = 2;
+ DOMAIN_NAMES = 3;
+ VIRTUAL_WORLDS = 4;
+ TRADING_CARDS = 5;
+ COLLECTABLES = 6;
+ SPORTS = 7;
+ UTILITY = 8;
+ BADGES = 9;
+}
+
+message Metadata {
+ map value = 1;
+}
+
+message AddMintersInput {
+ MinterList minter_list = 1;
+ string symbol = 2;
+}
+
+message RemoveMintersInput {
+ MinterList minter_list = 1;
+ string symbol = 2;
+}
+
+message GetNFTInfoInput {
+ string symbol = 1;
+ int64 token_id = 2;
+}
+
+message RecastInput {
+ string symbol = 1;
+ int64 token_id = 2;
+ string uri = 3;
+ string alias = 4;
+ Metadata metadata = 5;
+}
+
+message AssembledNfts {
+ map value = 1;
+}
+
+message AssembledFts {
+ map value = 1;
+}
+
+message AddNFTTypeInput {
+ string full_name = 1;
+ string short_name = 2;
+}
+
+// Events
+
+message NFTProtocolCreated {
+ option (aelf.is_event) = true;
+ // The symbol of this protocol.
+ string symbol = 1;
+ // The name of this protocol.
+ string protocol_name = 2;
+ // The total supply of the token.
+ int64 total_supply = 3;
+ // The address that created the token.
+ aelf.Address creator = 4;
+ // A flag indicating if this token is burnable.
+ bool is_burnable = 5;
+ // The chain id of the token.
+ int32 issue_chain_id = 6;
+ // The metadata of the token.
+ Metadata metadata = 7;
+ // Base Uri.
+ string base_uri = 8;
+ // Is token id can be reused.
+ bool is_token_id_reuse = 9;
+ string nft_type = 10;
+}
+
+message NFTMinted {
+ option (aelf.is_event) = true;
+ // The symbol of this protocol.
+ string symbol = 1;
+ // The name of this protocol.
+ string protocol_name = 2;
+ // Actually is the order of this token.
+ int64 token_id = 3;
+ // The address that creat the base token.
+ aelf.Address creator = 4;
+ // The address that mint this token.
+ aelf.Address minter = 5;
+ // The metadata of the token.
+ Metadata metadata = 6;
+ // The current owner of this nft.
+ aelf.Address owner = 7;
+ // Token Uri.
+ string uri = 8;
+ // Base Uri.
+ string base_uri = 9;
+ // Alias
+ string alias = 10;
+ // NFT Type
+ string nft_type = 11;
+ // Quantity
+ int64 quantity = 12;
+ int64 total_quantity = 13;
+ aelf.Hash token_hash = 14;
+}
+
+message Transferred {
+ option (aelf.is_event) = true;
+ aelf.Address from = 1 [(aelf.is_indexed) = true];
+ aelf.Address to = 2 [(aelf.is_indexed) = true];
+ string symbol = 3 [(aelf.is_indexed) = true];
+ int64 token_id = 4 [(aelf.is_indexed) = true];
+ int64 amount = 5;
+ string memo = 6;
+}
+
+message Approved {
+ option (aelf.is_event) = true;
+ aelf.Address owner = 1 [(aelf.is_indexed) = true];
+ aelf.Address spender = 2 [(aelf.is_indexed) = true];
+ string symbol = 3 [(aelf.is_indexed) = true];
+ int64 token_id = 4 [(aelf.is_indexed) = true];
+ int64 amount = 5;
+}
+
+message UnApproved {
+ option (aelf.is_event) = true;
+ aelf.Address owner = 1 [(aelf.is_indexed) = true];
+ aelf.Address spender = 2 [(aelf.is_indexed) = true];
+ string symbol = 3 [(aelf.is_indexed) = true];
+ int64 token_id = 4 [(aelf.is_indexed) = true];
+ int64 current_allowance = 5;
+}
+
+message Burned {
+ option (aelf.is_event) = true;
+ aelf.Address burner = 1 [(aelf.is_indexed) = true];
+ string symbol = 2 [(aelf.is_indexed) = true];
+ int64 token_id = 3 [(aelf.is_indexed) = true];
+ int64 amount = 4;
+}
+
+message Recasted {
+ option (aelf.is_event) = true;
+ string symbol = 1 [(aelf.is_indexed) = true];
+ int64 token_id = 2 [(aelf.is_indexed) = true];
+ Metadata old_metadata = 3 [(aelf.is_indexed) = true];
+ Metadata new_metadata = 4 [(aelf.is_indexed) = true];
+ string alias = 5 [(aelf.is_indexed) = true];
+ string uri = 6 [(aelf.is_indexed) = true];
+}
+
+message Assembled {
+ option (aelf.is_event) = true;
+ string symbol = 1 [(aelf.is_indexed) = true];
+ int64 token_id = 2 [(aelf.is_indexed) = true];
+ AssembledNfts assembled_nfts = 3 [(aelf.is_indexed) = true];
+ AssembledFts assembled_fts = 4 [(aelf.is_indexed) = true];
+}
+
+message Disassembled {
+ option (aelf.is_event) = true;
+ string symbol = 1 [(aelf.is_indexed) = true];
+ int64 token_id = 2 [(aelf.is_indexed) = true];
+ AssembledNfts disassembled_nfts = 3 [(aelf.is_indexed) = true];
+ AssembledFts disassembled_fts = 4 [(aelf.is_indexed) = true];
+}
+
+message NFTTypeAdded {
+ option (aelf.is_event) = true;
+ string full_name = 1;
+ string short_name = 2;
+}
+
+message NFTTypeRemoved {
+ option (aelf.is_event) = true;
+ string short_name = 1;
+}
+
+message MinterListAdded {
+ option (aelf.is_event) = true;
+ MinterList minter_list = 1;
+ string symbol = 2;
+}
+
+message MinterListRemoved {
+ option (aelf.is_event) = true;
+ MinterList minter_list = 1;
+ string symbol = 2;
+}
\ No newline at end of file
diff --git a/src/AElf.Client.Protobuf/Protobuf/receipt_maker.proto b/src/AElf.Client.Protobuf/Protobuf/receipt_maker.proto
new file mode 100644
index 0000000..3adefd5
--- /dev/null
+++ b/src/AElf.Client.Protobuf/Protobuf/receipt_maker.proto
@@ -0,0 +1,35 @@
+syntax = "proto3";
+
+import "aelf/core.proto";
+import "aelf/options.proto";
+import "google/protobuf/empty.proto";
+import "google/protobuf/wrappers.proto";
+
+option csharp_namespace = "AElf.Contracts.ReceiptMakerContract";
+
+service ReceiptMakerContract {
+ rpc GetReceiptCount(google.protobuf.Int64Value) returns (google.protobuf.Int64Value) {
+ option (aelf.is_view) = true;
+ }
+ rpc GetReceiptHash(GetReceiptHashInput) returns (aelf.Hash) {
+ option (aelf.is_view) = true;
+ }
+ rpc GetReceiptHashList(GetReceiptHashListInput) returns (GetReceiptHashListOutput) {
+ option (aelf.is_view) = true;
+ }
+}
+
+message GetReceiptHashInput {
+ int64 recorder_id = 1;
+ int64 receipt_id = 2;
+}
+
+message GetReceiptHashListInput {
+ int64 first_leaf_index = 1;
+ int64 last_leaf_index = 2;
+ int64 recorder_id = 3;
+}
+
+message GetReceiptHashListOutput {
+ repeated aelf.Hash receipt_hash_list = 1;
+}
\ No newline at end of file
diff --git a/src/AElf.Client.Protobuf/Protobuf/token_contract.proto b/src/AElf.Client.Protobuf/Protobuf/token_contract.proto
index 93d1433..90c1945 100644
--- a/src/AElf.Client.Protobuf/Protobuf/token_contract.proto
+++ b/src/AElf.Client.Protobuf/Protobuf/token_contract.proto
@@ -124,7 +124,15 @@ service TokenContract {
// This method is used to initialize the governance organization for some functions,
// including: the coefficient of the user transaction fee calculation formula,
// the coefficient of the contract developer resource fee calculation formula, and the side chain rental fee.
- rpc InitializeAuthorizedController(google.protobuf.Empty) returns (google.protobuf.Empty){
+ rpc InitializeAuthorizedController (google.protobuf.Empty) returns (google.protobuf.Empty){
+ }
+
+ rpc ResetExternalInfo (ResetExternalInfoInput) returns (google.protobuf.Empty){
+ }
+
+ rpc AddAddressToCreateTokenWhiteList (aelf.Address) returns (google.protobuf.Empty) {
+ }
+ rpc RemoveAddressFromCreateTokenWhiteList (aelf.Address) returns (google.protobuf.Empty) {
}
// Query token information.
@@ -200,6 +208,12 @@ service TokenContract {
rpc IsTokenAvailableForMethodFee (google.protobuf.StringValue) returns (google.protobuf.BoolValue) {
option (aelf.is_view) = true;
}
+ rpc IsInCreateTokenWhiteList (aelf.Address) returns (google.protobuf.BoolValue) {
+ option (aelf.is_view) = true;
+ }
+ rpc GetReservedExternalInfoKeyList (google.protobuf.Empty) returns (StringList) {
+ option (aelf.is_view) = true;
+ }
}
message TokenInfo {
@@ -221,6 +235,12 @@ message TokenInfo {
int32 issue_chain_id = 8;
// The amount of issued tokens.
int64 issued = 9;
+ // The external information of the token.
+ ExternalInfo external_info = 10;
+}
+
+message ExternalInfo {
+ map value = 1;
}
message CreateInput {
@@ -240,6 +260,8 @@ message CreateInput {
repeated aelf.Address lock_white_list = 7;
// The chain id of the token.
int32 issue_chain_id = 8;
+ // The external information of the token.
+ ExternalInfo external_info = 9;
}
message SetPrimaryTokenSymbolInput {
@@ -462,6 +484,11 @@ message ChargeTransactionFeesOutput {
string charging_information = 2;
}
+message CallbackInfo {
+ aelf.Address contract_address = 1;
+ string method_name = 2;
+}
+
message ExtraTokenListModified {
option (aelf.is_event) = true;
// Transaction fee token information.
@@ -592,6 +619,15 @@ message ChangeTokenIssuerInput
aelf.Address new_token_Issuer = 2;
}
+message ResetExternalInfoInput {
+ string symbol = 1;
+ ExternalInfo external_info = 2;
+}
+
+message StringList {
+ repeated string value = 1;
+}
+
message Transferred {
option (aelf.is_event) = true;
// The source address of the transferred token.
@@ -647,7 +683,6 @@ message ChainPrimaryTokenSymbolSet {
string token_symbol = 1;
}
-
message CalculateFeeAlgorithmUpdated {
option (aelf.is_event) = true;
// All calculate fee coefficients after modification.
@@ -686,6 +721,8 @@ message TokenCreated {
bool is_burnable = 6;
// The chain id of the token.
int32 issue_chain_id = 7;
+ // The external information of the token.
+ ExternalInfo external_info = 8;
}
message Issued {
@@ -736,4 +773,10 @@ message CrossChainReceived {
int32 issue_chain_id = 7;
// The parent chain height of the transfer transaction.
int64 parent_chain_height = 8;
+}
+
+message ExternalInfoChanged {
+ option (aelf.is_event) = true;
+ string symbol = 1;
+ ExternalInfo external_info = 2;
}
\ No newline at end of file
diff --git a/src/AElf.Client.Protobuf/Protobuf/token_contract_impl.proto b/src/AElf.Client.Protobuf/Protobuf/token_contract_impl.proto
new file mode 100644
index 0000000..cfc91fc
--- /dev/null
+++ b/src/AElf.Client.Protobuf/Protobuf/token_contract_impl.proto
@@ -0,0 +1,240 @@
+/**
+ * MultiToken contract.
+ *
+ * The MultiToken contract is mainly used to manage the user's account and transaction fees related Settings.
+ *
+ * Implement AElf Standards ACS1 and ACS2.
+ */
+syntax = "proto3";
+
+package tokenimpl;
+
+import "aelf/core.proto";
+import "acs1.proto";
+import "acs2.proto";
+import "token_contract.proto";
+// Because implementation uses this proto file.
+import "transaction_fee.proto";
+import "authority_info.proto";
+
+option csharp_namespace = "AElf.Contracts.MultiToken";
+
+service TokenContractImpl {
+ option (aelf.csharp_state) = "AElf.Contracts.MultiToken.TokenContractState";
+ option (aelf.base) = "acs1.proto";
+ option (aelf.base) = "acs2.proto";
+ option (aelf.base) = "token_contract.proto";
+
+ // Transfer resource tokens to designated contract address.
+ rpc AdvanceResourceToken (AdvanceResourceTokenInput) returns (google.protobuf.Empty) {
+ }
+
+ // Take token from contract address.
+ rpc TakeResourceTokenBack (TakeResourceTokenBackInput) returns (google.protobuf.Empty) {
+ }
+
+ // Register the token contract address for cross chain.
+ rpc RegisterCrossChainTokenContractAddress (RegisterCrossChainTokenContractAddressInput) returns (google.protobuf.Empty) {
+ }
+
+ // Set the receiver address of the side chain transaction fee.
+ rpc SetFeeReceiver (aelf.Address) returns (google.protobuf.Empty) {
+ }
+
+ // Validates if the token exist.
+ rpc ValidateTokenInfoExists(ValidateTokenInfoExistsInput) returns (google.protobuf.Empty){
+ }
+
+ // Update the rental unit price of the side chain.
+ rpc UpdateRental (UpdateRentalInput) returns (google.protobuf.Empty) {
+ }
+
+ // Set the amount of resources fee per minute for the side chain.
+ rpc UpdateRentedResources (UpdateRentedResourcesInput) returns (google.protobuf.Empty) {
+ }
+
+ // Transfer Token to the specified contract.
+ rpc TransferToContract (TransferToContractInput) returns (google.protobuf.Empty) {
+ }
+
+ // Change the governance organization of side chain rental.
+ rpc ChangeSideChainRentalController (AuthorityInfo) returns (google.protobuf.Empty) {
+ }
+
+ // Change the governance organization for tokens to pay transaction fees.
+ rpc ChangeSymbolsToPayTXSizeFeeController(AuthorityInfo) returns (google.protobuf.Empty){
+ }
+
+ // Change the governance organization for cross-chain token contract address registration.
+ rpc ChangeCrossChainTokenContractRegistrationController (AuthorityInfo) returns (google.protobuf.Empty) {
+ }
+
+ // Change the governance organization of the coefficient of the user transaction fee calculation formula.
+ rpc ChangeUserFeeController (AuthorityInfo) returns (google.protobuf.Empty) {
+ }
+
+ // Change the governance organization of the coefficient of the developer's transaction resource fee calculation formula.
+ rpc ChangeDeveloperController (AuthorityInfo) returns (google.protobuf.Empty) {
+ }
+
+ // Get the address of fee receiver.
+ rpc GetFeeReceiver (google.protobuf.Empty) returns (aelf.Address){
+ option (aelf.is_view) = true;
+ }
+
+ // Query the amount of resources usage currently.
+ rpc GetResourceUsage (google.protobuf.Empty) returns (ResourceUsage) {
+ option (aelf.is_view) = true;
+ }
+
+ // Query the governance organization for tokens to pay transaction fees.
+ rpc GetSymbolsToPayTXSizeFeeController(google.protobuf.Empty) returns (AuthorityInfo){
+ option (aelf.is_view) = true;
+ }
+
+ // Query the governance organization of the
+ rpc GetCrossChainTokenContractRegistrationController (google.protobuf.Empty) returns (AuthorityInfo) {
+ option (aelf.is_view) = true;
+ }
+
+ // Query the governance organization that calculates the formula coefficient
+ // for the transaction cost the user sends the contract.
+ rpc GetUserFeeController(google.protobuf.Empty) returns (UserFeeController){
+ option (aelf.is_view) = true;
+ }
+
+ // Query the governing organization of the formula coefficients for calculating developer contract transaction fee.
+ rpc GetDeveloperFeeController (google.protobuf.Empty) returns (DeveloperFeeController) {
+ option (aelf.is_view) = true;
+ }
+
+ // Query the organization that governs the side chain rental fee.
+ rpc GetSideChainRentalControllerCreateInfo (google.protobuf.Empty) returns (AuthorityInfo) {
+ option (aelf.is_view) = true;
+ }
+
+ // Compute the virtual address for locking.
+ rpc GetVirtualAddressForLocking (GetVirtualAddressForLockingInput) returns (aelf.Address) {
+ option (aelf.is_view) = true;
+ }
+
+ // Query how much resource tokens should be paid currently.
+ rpc GetOwningRental (google.protobuf.Empty) returns (OwningRental) {
+ option (aelf.is_view) = true;
+ }
+
+ // Query the unit price of the side chain resource cost, resource cost = unit price * quantity,
+ // the quantity can be queried through GetResourceUsage.
+ rpc GetOwningRentalUnitValue (google.protobuf.Empty) returns (OwningRentalUnitValue) {
+ option (aelf.is_view) = true;
+ }
+}
+
+message AdvanceResourceTokenInput {
+ // The contract address to transfer.
+ aelf.Address contract_address = 1;
+ // The resource token symbol to transfer.
+ string resource_token_symbol = 2;
+ // The amount of resource token to transfer.
+ int64 amount = 3;
+}
+
+message TakeResourceTokenBackInput {
+ // The contract address to take back.
+ aelf.Address contract_address = 1;
+ // The resource token symbol to take back.
+ string resource_token_symbol = 2;
+ // The amount of resource token to take back.
+ int64 amount = 3;
+}
+
+message RegisterCrossChainTokenContractAddressInput{
+ // The source chain id.
+ int32 from_chain_id = 1;
+ // The parent chain height of the transaction.
+ int64 parent_chain_height = 2;
+ // The raw bytes of the transfer transaction.
+ bytes transaction_bytes = 3;
+ // The merkle path created from the transaction.
+ aelf.MerklePath merkle_path = 4;
+ // The token contract address.
+ aelf.Address token_contract_address = 5;
+}
+
+message ValidateTokenInfoExistsInput{
+ // The symbol of the token.
+ string symbol = 1;
+ // The full name of the token.
+ string token_name = 2;
+ // The total supply of the token.
+ int64 total_supply = 3;
+ // The precision of the token.
+ int32 decimals = 4;
+ // The address that created the token.
+ aelf.Address issuer = 5;
+ // A flag indicating if this token is burnable.
+ bool is_burnable = 6;
+ // The chain id of the token.
+ int32 issue_chain_id = 7;
+ // The external information of the token.
+ map external_info = 8;
+}
+
+message UpdateRentalInput {
+ // The unit price of resource tokens, symbol -> unit price.
+ map rental = 1;
+}
+
+message UpdateRentedResourcesInput {
+ // Amount of resource tokens consumed per minute, symbol -> resource consumption.
+ map resource_amount = 1;
+}
+
+message ResourceUsage {
+ // The amount of resource tokens usage, symbol -> amount.
+ map value = 1;
+}
+
+message GetVirtualAddressForLockingInput {
+ // The address of the lock.
+ aelf.Address address = 1;
+ // The id of the lock.
+ aelf.Hash lock_id = 2;
+}
+
+message OwningRental {
+ // The amount of resource tokens owed, symbol -> amount.
+ map resource_amount = 1;
+}
+
+message OwningRentalUnitValue {
+ // Resource unit price, symbol -> unit price.
+ map resource_unit_value = 1;
+}
+
+message TransferToContractInput {
+ // The symbol of token.
+ string symbol = 1;
+ // The amount of token.
+ int64 amount = 2;
+ // The memo.
+ string memo = 3;
+}
+
+message UserFeeController{
+ // The association that governs the organization.
+ AuthorityInfo root_controller = 1;
+ // The parliament organization of members.
+ AuthorityInfo parliament_controller = 2;
+ // The referendum organization of members.
+ AuthorityInfo referendum_controller = 3;
+}
+
+message DeveloperFeeController {
+ // The association that governs the organization.
+ AuthorityInfo root_controller = 1;
+ // The parliament organization of members.
+ AuthorityInfo parliament_controller = 2;
+ // The developer organization of members.
+ AuthorityInfo developer_controller = 3;
+}
diff --git a/src/AElf.Client.Protobuf/Protobuf/whitelist_contract.proto b/src/AElf.Client.Protobuf/Protobuf/whitelist_contract.proto
new file mode 100644
index 0000000..37ce7af
--- /dev/null
+++ b/src/AElf.Client.Protobuf/Protobuf/whitelist_contract.proto
@@ -0,0 +1,581 @@
+syntax = "proto3";
+
+package whitelist;
+
+import "aelf/core.proto";
+import "aelf/options.proto";
+import "google/protobuf/empty.proto";
+import "google/protobuf/wrappers.proto";
+import "acs1.proto";
+
+option csharp_namespace = "AElf.Contracts.Whitelist";
+
+service WhitelistContract {
+ option (aelf.csharp_state) = "AElf.Contracts.Whitelist.WhitelistContractState";
+ option (aelf.base) = "acs1.proto";
+
+ rpc Initialize (google.protobuf.Empty) returns (google.protobuf.Empty) {
+ }
+
+ //For Managers.
+ //Create whitelist.
+ rpc CreateWhitelist (CreateWhitelistInput) returns (aelf.Hash){
+ }
+
+ //Add tag info or extraInfo.
+ rpc AddExtraInfo (AddExtraInfoInput) returns (aelf.Hash){
+ }
+
+ //Add multiple addresses to an existing whitelist.
+ rpc AddAddressInfoListToWhitelist (AddAddressInfoListToWhitelistInput) returns (google.protobuf.Empty){
+ }
+
+ //Remove multiple addresses from an existing whitelist.
+ rpc RemoveAddressInfoListFromWhitelist (RemoveAddressInfoListFromWhitelistInput) returns (google.protobuf.Empty){
+ }
+
+ //Remove tag info.
+ rpc RemoveTagInfo (RemoveTagInfoInput) returns (google.protobuf.Empty){
+ }
+
+ //Disable whitelist according to the whitelist_id.
+ rpc DisableWhitelist (aelf.Hash) returns (google.protobuf.Empty){
+ }
+
+ //Re-enable whitelist according to the whitelist_id.
+ rpc EnableWhitelist (aelf.Hash) returns (google.protobuf.Empty){
+ }
+
+ //Update state: Whether the whitelist is allowed to be cloned.
+ rpc ChangeWhitelistCloneable(ChangeWhitelistCloneableInput) returns (google.protobuf.Empty){
+ }
+
+ //Update whitelist extraInfo according to the whitelist_id and extraInfo.
+ rpc UpdateExtraInfo (UpdateExtraInfoInput) returns (google.protobuf.Empty){
+ }
+
+ //Transfer Manager.
+ rpc TransferManager (TransferManagerInput) returns (google.protobuf.Empty){
+ }
+
+ //Add manager.
+ rpc AddManagers (AddManagersInput) returns (google.protobuf.Empty){
+ }
+
+ //Remove manager.
+ rpc RemoveManagers (RemoveManagersInput) returns (google.protobuf.Empty){
+ }
+
+ //Reset whitelist according to the whitelist_id and project_id.
+ rpc ResetWhitelist (ResetWhitelistInput) returns (google.protobuf.Empty){
+ }
+
+
+ //For Subscribers.
+ //Subscribe whitelist.
+ rpc SubscribeWhitelist (SubscribeWhitelistInput) returns (aelf.Hash){
+ }
+
+ // Cancel subscribe according to the subscribe_id.
+ rpc UnsubscribeWhitelist (aelf.Hash) returns (google.protobuf.Empty){
+ }
+
+ //After used,address and extra info will be added into the consumedList.
+ rpc ConsumeWhitelist (ConsumeWhitelistInput) returns (google.protobuf.Empty){
+ }
+
+ //Clone whitelist.
+ rpc CloneWhitelist (CloneWhitelistInput) returns (aelf.Hash){
+ }
+
+ //Add subscribe whitelist manager.
+ rpc AddSubscribeManagers (AddSubscribeManagersInput) returns (google.protobuf.Empty){
+ }
+
+ //Remove subscribe whitelist manager.
+ rpc RemoveSubscribeManagers (RemoveSubscribeManagersInput) returns (google.protobuf.Empty){
+ }
+
+
+ //Views.
+ //Get whitelist_id list according to the manager.
+ rpc GetWhitelistByManager (aelf.Address) returns (WhitelistIdList){
+ option (aelf.is_view) = true;
+ }
+
+ //Get existing whitelist according to the whitelist_id.
+ rpc GetWhitelist (aelf.Hash) returns (WhitelistInfo){
+ option (aelf.is_view) = true;
+ }
+
+ //Get whitelist detail extraInfo according to the whitelist_id.
+ rpc GetWhitelistDetail (aelf.Hash) returns(ExtraInfoList){
+ option (aelf.is_view) = true;
+ }
+
+ //Get whitelist id by project_id.
+ rpc GetWhitelistByProject(aelf.Hash) returns (WhitelistIdList){
+ option (aelf.is_view) = true;
+ }
+
+ //Get extraInfo according to the tag_id.
+ rpc GetExtraInfoByTag (GetExtraInfoByTagInput) returns (ExtraInfo){
+ option (aelf.is_view) = true;
+ }
+
+ //Get tag info according to the tag_info_id.
+ rpc GetTagInfoByHash (aelf.Hash) returns (TagInfo){
+ option (aelf.is_view) = true;
+ }
+
+ //Get tagInfoId list according to the whitelist_id and project_id.
+ rpc GetExtraInfoIdList(GetExtraInfoIdListInput) returns (HashList){
+ option (aelf.is_view) = true;
+ }
+
+ //Get tagId according to the whitelist_id and address.
+ rpc GetTagIdByAddress(GetTagIdByAddressInput) returns (aelf.Hash){
+ option (aelf.is_view) = true;
+ }
+
+ //Get TagInfo according to the address and whitelist_id.
+ rpc GetExtraInfoByAddress(GetExtraInfoByAddressInput) returns (TagInfo){
+ option (aelf.is_view) = true;
+ }
+
+ //Whether the address exists in the whitelist according to the whitelist_id and address.
+ rpc GetAddressFromWhitelist(GetAddressFromWhitelistInput) returns (google.protobuf.BoolValue){
+ option (aelf.is_view) = true;
+ }
+
+ //Whether the extraInfo (address+TagInfoId) exists in the whitelist according to the whitelist_id and address.
+ rpc GetExtraInfoFromWhitelist(GetExtraInfoFromWhitelistInput) returns (google.protobuf.BoolValue){
+ option (aelf.is_view) = true;
+ }
+
+ //Whether the tagInfo exists in the whitelist according to the whitelist_id,project_id,tagInfo(tagName,info).
+ rpc GetTagInfoFromWhitelist(GetTagInfoFromWhitelistInput) returns (google.protobuf.BoolValue){
+ option (aelf.is_view) = true;
+ }
+
+ //Get manager list according to the whitelist_id.
+ rpc GetManagerList(aelf.Hash) returns (AddressList){
+ option (aelf.is_view) = true;
+ }
+
+ //Get subscribe manager list according to the subscribe_id.
+ rpc GetSubscribeManagerList(aelf.Hash) returns (AddressList){
+ option (aelf.is_view) = true;
+ }
+
+ //Whether manager exist in whitelist.
+ rpc GetManagerExistFromWhitelist(GetManagerExistFromWhitelistInput) returns (google.protobuf.BoolValue){
+ option (aelf.is_view) = true;
+ }
+
+ //Get subscribe whitelist info according to the subscribe_id.
+ rpc GetSubscribeWhitelist (aelf.Hash) returns (SubscribeWhitelistInfo){
+ option (aelf.is_view) = true;
+ }
+
+ //Get subscribe_id list according to the manager.
+ rpc GetSubscribeIdByManager (aelf.Address) returns (HashList){
+ option (aelf.is_view) = true;
+ }
+
+ //Get consumed list according to the subscribe_id.
+ rpc GetConsumedList (aelf.Hash) returns (ConsumedList){
+ option (aelf.is_view) = true;
+ }
+
+ //After consumed,get available whitelist according to the subscribe_id.
+ rpc GetAvailableWhitelist (aelf.Hash) returns (ExtraInfoIdList){
+ option (aelf.is_view) = true;
+ }
+
+ //Whether the extraInfo exist in the available whitelist.
+ rpc GetFromAvailableWhitelist (GetFromAvailableWhitelistInput) returns (google.protobuf.BoolValue){
+ option (aelf.is_view) = true;
+ }
+
+
+}
+
+//Structs.
+
+message WhitelistInfo {
+ //The whitelist id.
+ aelf.Hash whitelist_id = 1;
+ //The project id.
+ aelf.Hash project_id = 2;
+ //The list of address and extra info in this whitelist.
+ ExtraInfoIdList extra_info_id_list = 3;
+ //Whether the whitelist is available.
+ bool is_available = 4;
+ //Whether the whiteList can be cloned.
+ bool is_cloneable = 5;
+ string remark = 6;
+ aelf.Hash clone_from = 7;
+ aelf.Address creator = 8;
+ AddressList manager = 9;
+ StrategyType strategy_type = 10;
+}
+
+//Pricing strategy
+message PriceTag{
+ string symbol = 1;
+ int64 amount = 2;
+}
+
+enum StrategyType{
+ Basic = 0;
+ Price = 1;
+ Customize = 2;
+}
+
+message ExtraInfoIdList {
+ repeated ExtraInfoId value = 1;
+}
+
+message ExtraInfoId {
+ AddressList address_list = 1;
+ aelf.Hash id = 2;
+}
+
+message ExtraInfoList {
+ repeated ExtraInfo value = 1;
+}
+
+message ExtraInfo {
+ AddressList address_list = 1;
+ TagInfo info = 2;
+}
+
+message TagInfo {
+ string tag_name = 1;
+ bytes info = 2;
+}
+
+message TagInfoList{
+ repeated TagInfo value = 1;
+}
+
+message WhitelistIdList{
+ repeated aelf.Hash whitelist_id = 1;
+}
+
+message SubscribeWhitelistInfo {
+ //The subscribe id.
+ aelf.Hash subscribe_id = 1;
+ //The project id.
+ aelf.Hash project_id = 2;
+ //The whitelist id.
+ aelf.Hash whitelist_id = 3;
+ aelf.Address subscriber = 4;
+ //Manager list.
+ AddressList manager_list = 5;
+}
+
+message ConsumedList {
+ //The subscribe id.
+ aelf.Hash subscribe_id = 1;
+ //The whitelist id.
+ aelf.Hash whitelist_id = 2;
+ //The consumed address and extra info list in this whitelist.
+ ExtraInfoIdList extra_info_id_list = 3;
+}
+
+message AddressList {
+ repeated aelf.Address value = 1;
+}
+
+message HashList{
+ repeated aelf.Hash value = 1;
+}
+
+//Inputs.
+
+//message InitializeInput{
+//
+//}
+
+message CreateWhitelistInput {
+ ExtraInfoList extra_info_list = 1;
+ bool is_cloneable = 2;
+ string remark = 3;
+ aelf.Address creator = 4;
+ AddressList manager_list = 5;
+ aelf.Hash project_id = 6;
+ StrategyType strategy_type = 7;
+}
+
+message AddAddressInfoListToWhitelistInput {
+ aelf.Hash whitelist_id = 1;
+ ExtraInfoIdList extra_info_id_list = 2;
+}
+
+message RemoveAddressInfoListFromWhitelistInput{
+ aelf.Hash whitelist_id = 1;
+ ExtraInfoIdList extra_info_id_list = 2;
+}
+
+message ChangeWhitelistCloneableInput{
+ aelf.Hash whitelist_id = 1;
+ bool is_cloneable = 2;
+}
+
+message AddExtraInfoInput{
+ aelf.Hash whitelist_id = 1;
+ aelf.Hash project_id = 2;
+ TagInfo tag_info = 3;
+ AddressList address_list = 4;
+}
+
+message RemoveTagInfoInput{
+ aelf.Hash whitelist_id = 1;
+ aelf.Hash project_id = 2;
+ aelf.Hash tag_id = 3;
+}
+
+message UpdateExtraInfoInput{
+ aelf.Hash whitelist_id = 1;
+ ExtraInfoId extra_info_list = 2;
+}
+
+message SubscribeWhitelistInput{
+ //The project id.
+ aelf.Hash project_id = 1;
+ //The whitelist id.
+ aelf.Hash whitelist_id = 2;
+ //Subscriber.
+ aelf.Address subscriber = 3;
+ //Manager list.
+ AddressList manager_list = 4;
+}
+
+message ConsumeWhitelistInput{
+ aelf.Hash subscribe_id = 1;
+ aelf.Hash whitelist_id = 2;
+ ExtraInfoId extra_info_id = 3;
+}
+
+message CloneWhitelistInput{
+ aelf.Hash whitelist_id = 1;
+ aelf.Address creator = 2;
+ AddressList manager_list = 3;
+ aelf.Hash project_id = 4;
+}
+
+message TransferManagerInput{
+ aelf.Hash whitelist_id = 1;
+ aelf.Address manager = 2;
+}
+
+message GetFromAvailableWhitelistInput{
+ aelf.Hash subscribe_id = 1;
+ ExtraInfoId extra_info_id = 2;
+}
+
+message AddManagersInput{
+ aelf.Hash whitelist_id = 1;
+ AddressList manager_list = 2;
+}
+
+message AddSubscribeManagersInput{
+ aelf.Hash subscribe_id = 1;
+ AddressList manager_list = 2;
+}
+
+message RemoveManagersInput{
+ aelf.Hash whitelist_id = 1;
+ AddressList manager_list = 2;
+}
+
+message RemoveSubscribeManagersInput{
+ aelf.Hash subscribe_id = 1;
+ AddressList manager_list = 2;
+}
+
+message GetTagIdByAddressInput{
+ aelf.Hash whitelist_id = 1;
+ aelf.Address address = 2;
+}
+
+message GetExtraInfoByAddressInput{
+ aelf.Hash whitelist_id = 1;
+ aelf.Address address = 2;
+}
+
+message GetExtraInfoIdListInput{
+ aelf.Hash whitelist_id = 1;
+ aelf.Hash project_id = 2;
+}
+
+message GetExtraInfoByTagInput{
+ aelf.Hash whitelist_id = 1;
+ aelf.Hash tag_info_id = 2;
+}
+
+message GetAddressFromWhitelistInput{
+ aelf.Hash whitelist_id = 1;
+ aelf.Address address = 2;
+}
+
+message GetExtraInfoFromWhitelistInput{
+ aelf.Hash whitelist_id = 1;
+ ExtraInfoId extra_info_id = 2;
+}
+
+message GetTagInfoFromWhitelistInput{
+ aelf.Hash whitelist_id = 1;
+ aelf.Hash project_id = 2;
+ TagInfo tag_info = 3;
+}
+
+message GetManagerExistFromWhitelistInput{
+ aelf.Hash whitelist_id = 1;
+ aelf.Address manager = 2;
+}
+
+message ResetWhitelistInput{
+ aelf.Hash whitelist_id = 1;
+ aelf.Hash project_id = 2;
+}
+
+//Events.
+
+message WhitelistCreated {
+ option (aelf.is_event) = true;
+ //The whitelist id.
+ aelf.Hash whitelist_id = 1;
+ //The list of address and extra info in this whitelist.
+ ExtraInfoIdList extra_info_id_list = 2;
+ //Whether the whitelist is available.
+ bool is_available = 3;
+ bool is_cloneable = 4;
+ string remark = 5;
+ aelf.Hash clone_from = 6;
+ aelf.Address creator = 7;
+ AddressList manager = 8;
+ aelf.Hash project_id = 9;
+ StrategyType strategy_type = 10;
+
+}
+
+message WhitelistSubscribed {
+ option (aelf.is_event) = true;
+ //The subscribe id.
+ aelf.Hash subscribe_id = 1;
+ //The project id.
+ aelf.Hash project_id = 2;
+ //The whitelist id.
+ aelf.Hash whitelist_id = 3;
+ //Subscriber.
+ aelf.Address subscriber = 4;
+ //Manager list.
+ AddressList manager_list = 5;
+}
+
+message WhitelistUnsubscribed{
+ option (aelf.is_event) = true;
+ aelf.Hash subscribe_id = 1;
+ aelf.Hash project_id = 2;
+ aelf.Hash whitelist_id = 3;
+}
+
+message WhitelistAddressInfoAdded {
+ option (aelf.is_event) = true;
+ aelf.Hash whitelist_id = 1;
+ ExtraInfoIdList extra_info_id_list = 2;
+}
+
+message WhitelistAddressInfoRemoved {
+ option (aelf.is_event) = true;
+ aelf.Hash whitelist_id = 1;
+ ExtraInfoIdList extra_info_id_list = 2;
+}
+
+message WhitelistDisabled {
+ option (aelf.is_event) = true;
+ aelf.Hash whitelist_id = 1;
+ bool is_available = 2;
+}
+
+message WhitelistReenable{
+ option (aelf.is_event) = true;
+ aelf.Hash whitelist_id = 1;
+ bool is_available = 2;
+}
+
+message ConsumedListAdded {
+ option (aelf.is_event) = true;
+ aelf.Hash subscribe_id = 1;
+ aelf.Hash whitelist_id = 2;
+ ExtraInfoIdList extra_info_id_list = 3;
+}
+
+message IsCloneableChanged{
+ option (aelf.is_event) = true;
+ aelf.Hash whitelist_id = 1;
+ bool is_cloneable = 2;
+}
+
+message TagInfoAdded{
+ option (aelf.is_event) = true;
+ aelf.Hash tag_info_id = 1;
+ TagInfo tag_info = 2;
+ aelf.Hash project_id = 3;
+ aelf.Hash whitelist_id = 4;
+}
+
+message TagInfoRemoved{
+ option (aelf.is_event) = true;
+ aelf.Hash tag_info_id = 1;
+ TagInfo tag_info = 2;
+ aelf.Hash project_id = 3;
+ aelf.Hash whitelist_id = 4;
+}
+
+message ExtraInfoUpdated {
+ option (aelf.is_event) = true;
+ aelf.Hash whitelist_id = 1;
+ ExtraInfoId extra_info_id_before = 2;
+ ExtraInfoId extra_info_id_after = 3;
+}
+
+message ManagerTransferred{
+ option (aelf.is_event) = true;
+ aelf.Hash whitelist_id = 1;
+ aelf.Address transfer_from = 2;
+ aelf.Address transfer_to = 3;
+}
+
+message ManagerAdded{
+ option (aelf.is_event) = true;
+ aelf.Hash whitelist_id = 1;
+ AddressList manager_list = 2;
+}
+
+message ManagerRemoved{
+ option (aelf.is_event) = true;
+ aelf.Hash whitelist_id = 1;
+ AddressList manager_list = 2;
+}
+
+message WhitelistReset{
+ option (aelf.is_event) = true;
+ aelf.Hash whitelist_id = 1;
+ aelf.Hash project_id = 2;
+}
+
+message SubscribeManagerAdded{
+ option (aelf.is_event) = true;
+ aelf.Hash subscribe_id = 1;
+ AddressList manager_list = 2;
+}
+
+message SubscribeManagerRemoved{
+ option (aelf.is_event) = true;
+ aelf.Hash subscribe_id = 1;
+ AddressList manager_list = 2;
+}
\ No newline at end of file
diff --git a/src/AElf.Client/AElf.Client.csproj b/src/AElf.Client/AElf.Client.csproj
index ffb9f1b..e6ccb5c 100644
--- a/src/AElf.Client/AElf.Client.csproj
+++ b/src/AElf.Client/AElf.Client.csproj
@@ -15,9 +15,10 @@
-
-
-
+
+
+
+
diff --git a/src/AElf.Client/AElfClient.Chain.cs b/src/AElf.Client/AElfClient.Chain.cs
index e42eb0f..eeeb460 100644
--- a/src/AElf.Client/AElfClient.Chain.cs
+++ b/src/AElf.Client/AElfClient.Chain.cs
@@ -32,7 +32,7 @@ public async Task GetContractFileDescriptorSetAsync(string? address)
var set = await _httpService.GetResponseAsync(url);
if (set == null)
{
- throw new AElfClientException("Failed to get chain status");
+ throw new AElfClientException("Failed to get method descriptor");
}
return set;
diff --git a/src/AElf.Client/AElfClient.Client.cs b/src/AElf.Client/AElfClient.Client.cs
index c187395..fd455c2 100644
--- a/src/AElf.Client/AElfClient.Client.cs
+++ b/src/AElf.Client/AElfClient.Client.cs
@@ -12,257 +12,254 @@ namespace AElf.Client;
public partial class AElfClient : IClientService
{
///
- /// Verify whether this sdk successfully connects the chain.
- ///
- /// IsConnected or not
- public async Task IsConnectedAsync()
+ /// Verify whether this sdk successfully connects the chain.
+ ///
+ /// IsConnected or not
+ public async Task IsConnectedAsync()
+ {
+ try
{
- try
- {
- var chainStatus = await GetChainStatusAsync();
- return chainStatus != null;
- }
- catch (Exception)
- {
- return false;
- }
+ await GetChainStatusAsync();
+ return true;
}
-
- ///
- /// Get the address of genesis contract.
- ///
- /// Address
- public async Task GetGenesisContractAddressAsync()
+ catch (Exception)
{
- var statusDto = await GetChainStatusAsync();
- var genesisAddress = statusDto?.GenesisContractAddress;
- return genesisAddress;
+ return false;
}
+ }
+
+ ///
+ /// Get the address of genesis contract.
+ ///
+ /// Address
+ public async Task GetGenesisContractAddressAsync()
+ {
+ var statusDto = await GetChainStatusAsync();
+ var genesisAddress = statusDto.GenesisContractAddress;
+ return genesisAddress;
+ }
- ///
- /// Get address of a contract by given contractNameHash.
- ///
- ///
- /// Address
- public async Task GetContractAddressByNameAsync(Hash contractNameHash)
+ ///
+ /// Get address of a contract by given contractNameHash.
+ ///
+ ///
+ /// Address
+ public async Task GetContractAddressByNameAsync(Hash contractNameHash)
+ {
+ var from = GetAddressFromPrivateKey(AElfClientConstants.DefaultPrivateKey);
+ var to = await GetGenesisContractAddressAsync();
+ var transaction = await GenerateTransactionAsync(from, to, "GetContractAddressByName", contractNameHash);
+ var txWithSig = SignTransaction(AElfClientConstants.DefaultPrivateKey, transaction);
+
+ var response = await ExecuteTransactionAsync(new ExecuteTransactionDto
{
- var from = GetAddressFromPrivateKey(AElfClientConstants.DefaultPrivateKey);
- var to = await GetGenesisContractAddressAsync();
- var transaction = await GenerateTransactionAsync(from, to, "GetContractAddressByName", contractNameHash);
- var txWithSig = SignTransaction(AElfClientConstants.DefaultPrivateKey, transaction);
+ RawTransaction = txWithSig.ToByteArray().ToHex()
+ });
+ var byteArray = ByteArrayHelper.HexStringToByteArray(response);
+ var address = Address.Parser.ParseFrom(byteArray);
- var response = await ExecuteTransactionAsync(new ExecuteTransactionDto
+ return address;
+ }
+
+ ///
+ /// Build a transaction from the input parameters.
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// Transaction unsigned
+ public async Task GenerateTransactionAsync(string? from, string? to,
+ string methodName, IMessage input)
+ {
+ try
+ {
+ AssertValidAddress(to);
+ var chainStatus = await GetChainStatusAsync();
+ var transaction = new Transaction
{
- RawTransaction = txWithSig.ToByteArray().ToHex()
- });
- var byteArray = ByteArrayHelper.HexStringToByteArray(response);
- var address = Address.Parser.ParseFrom(byteArray);
+ From = from.ToAddress(),
+ To = Address.FromBase58(to),
+ MethodName = methodName,
+ Params = input.ToByteString(),
+ RefBlockNumber = chainStatus.BestChainHeight,
+ RefBlockPrefix = ByteString.CopyFrom(Hash.LoadFromHex(chainStatus.BestChainHash).Value
+ .Take(4).ToArray())
+ };
- return address;
+ return transaction;
}
-
- ///
- /// Build a transaction from the input parameters.
- ///
- ///
- ///
- ///
- ///
- /// Transaction unsigned
- public async Task GenerateTransactionAsync(string? from, string? to,
- string methodName, IMessage input)
+ catch (Exception ex)
{
- try
- {
- AssertValidAddress(to);
- var chainStatus = await GetChainStatusAsync();
- var transaction = new Transaction
- {
- From = from.ToAddress(),
- To = Address.FromBase58(to),
- MethodName = methodName,
- Params = input.ToByteString(),
- RefBlockNumber = chainStatus.BestChainHeight,
- RefBlockPrefix = ByteString.CopyFrom(Hash.LoadFromHex(chainStatus.BestChainHash).Value
- .Take(4).ToArray())
- };
-
- return transaction;
- }
- catch (Exception ex)
- {
- throw new AElfClientException($"Failed to generate transaction: {ex.Message}");
- }
+ throw new AElfClientException($"Failed to generate transaction: {ex.Message}");
}
+ }
- ///
- /// Convert the Address to the displayed string:symbol_base58-string_base58-string-chain-id
- ///
- ///
- ///
- public async Task GetFormattedAddressAsync(Address address)
+ ///
+ /// Convert the Address to the displayed string:symbol_base58-string_base58-string-chain-id
+ ///
+ ///
+ ///
+ public async Task GetFormattedAddressAsync(Address address)
+ {
+ var tokenContractAddress =
+ await GetContractAddressByNameAsync(HashHelper.ComputeFrom("AElf.ContractNames.Token"));
+ var fromAddress = GetAddressFromPrivateKey(AElfClientConstants.DefaultPrivateKey);
+ var toAddress = tokenContractAddress.ToBase58();
+ var methodName = "GetPrimaryTokenSymbol";
+ var param = new Empty();
+
+ var transaction = await GenerateTransactionAsync(fromAddress, toAddress, methodName, param);
+ var txWithSign = SignTransaction(AElfClientConstants.DefaultPrivateKey, transaction);
+
+ var result = await ExecuteTransactionAsync(new ExecuteTransactionDto
{
- var tokenContractAddress = await GetContractAddressByNameAsync(HashHelper.ComputeFrom("AElf.ContractNames.Token"));
- var fromAddress = GetAddressFromPrivateKey(AElfClientConstants.DefaultPrivateKey);
- var toAddress = tokenContractAddress.ToBase58();
- var methodName = "GetPrimaryTokenSymbol";
- var param = new Empty();
+ RawTransaction = txWithSign.ToByteArray().ToHex()
+ });
- var transaction = await GenerateTransactionAsync(fromAddress, toAddress, methodName, param);
- var txWithSign = SignTransaction(AElfClientConstants.DefaultPrivateKey, transaction);
+ var symbol = StringValue.Parser.ParseFrom(ByteArrayHelper.HexStringToByteArray(result));
+ var chainIdString = (await GetChainStatusAsync()).ChainId;
- var result = await ExecuteTransactionAsync(new ExecuteTransactionDto
- {
- RawTransaction = txWithSign.ToByteArray().ToHex()
- });
-
- var symbol = StringValue.Parser.ParseFrom(ByteArrayHelper.HexStringToByteArray(result));
- var chainIdString = (await GetChainStatusAsync())?.ChainId;
+ return $"{symbol.Value}_{address.ToBase58()}_{chainIdString}";
+ }
- return $"{symbol.Value}_{address.ToBase58()}_{chainIdString}";
- }
+ ///
+ /// Sign a transaction using private key.
+ ///
+ ///
+ ///
+ /// Transaction signed
+ public Transaction SignTransaction(string? privateKeyHex, Transaction transaction)
+ {
+ var transactionData = transaction.GetHash().ToByteArray();
- ///
- /// Sign a transaction using private key.
- ///
- ///
- ///
- /// Transaction signed
- public Transaction SignTransaction(string? privateKeyHex, Transaction transaction)
- {
- var transactionData = transaction.GetHash().ToByteArray();
+ privateKeyHex ??= AElfClientConstants.DefaultPrivateKey;
- privateKeyHex ??= AElfClientConstants.DefaultPrivateKey;
+ // Sign the hash
+ var privateKey = ByteArrayHelper.HexStringToByteArray(privateKeyHex);
+ var signature = CryptoHelper.SignWithPrivateKey(privateKey, transactionData);
+ transaction.Signature = ByteString.CopyFrom(signature);
- // Sign the hash
- var privateKey = ByteArrayHelper.HexStringToByteArray(privateKeyHex);
- var signature = CryptoHelper.SignWithPrivateKey(privateKey, transactionData);
- transaction.Signature = ByteString.CopyFrom(signature);
+ return transaction;
+ }
- return transaction;
- }
-
- ///
- /// Sign a transaction using private key.
- ///
- ///
- ///
- /// Transaction signed
- public Transaction SignTransaction(byte[]? privateKey, Transaction transaction)
- {
- var transactionData = transaction.GetHash().ToByteArray();
+ ///
+ /// Sign a transaction using private key.
+ ///
+ ///
+ ///
+ /// Transaction signed
+ public Transaction SignTransaction(byte[]? privateKey, Transaction transaction)
+ {
+ var transactionData = transaction.GetHash().ToByteArray();
- privateKey ??= ByteArrayHelper.HexStringToByteArray(AElfClientConstants.DefaultPrivateKey);
+ privateKey ??= ByteArrayHelper.HexStringToByteArray(AElfClientConstants.DefaultPrivateKey);
- // Sign the hash
- var signature = CryptoHelper.SignWithPrivateKey(privateKey, transactionData);
- transaction.Signature = ByteString.CopyFrom(signature);
+ // Sign the hash
+ var signature = CryptoHelper.SignWithPrivateKey(privateKey, transactionData);
+ transaction.Signature = ByteString.CopyFrom(signature);
- return transaction;
- }
+ return transaction;
+ }
- ///
- /// Get the account address through the public key.
- ///
- ///
- /// Account
- public string GetAddressFromPubKey(string pubKey)
- {
- var publicKey = ByteArrayHelper.HexStringToByteArray(pubKey);
- var address = Address.FromPublicKey(publicKey);
- return address.ToBase58();
- }
-
- ///
- /// Get the account address through the private key.
- ///
- ///
- ///
- public string? GetAddressFromPrivateKey(string? privateKeyHex)
- {
- var address = Address.FromPublicKey(GetAElfKeyPair(privateKeyHex).PublicKey);
- return address.ToBase58();
- }
+ ///
+ /// Get the account address through the public key.
+ ///
+ ///
+ /// Account
+ public string GetAddressFromPubKey(string pubKey)
+ {
+ var publicKey = ByteArrayHelper.HexStringToByteArray(pubKey);
+ var address = Address.FromPublicKey(publicKey);
+ return address.ToBase58();
+ }
- public Address GetBase58String(string base58String)
+ ///
+ /// Get the account address through the private key.
+ ///
+ ///
+ ///
+ public string? GetAddressFromPrivateKey(string? privateKeyHex)
+ {
+ var address = Address.FromPublicKey(GetAElfKeyPair(privateKeyHex).PublicKey);
+ return address.ToBase58();
+ }
+
+ public KeyPairInfo GenerateKeyPairInfo()
+ {
+ var keyPair = CryptoHelper.GenerateKeyPair();
+ var privateKey = keyPair.PrivateKey.ToHex();
+ var publicKey = keyPair.PublicKey.ToHex();
+ var address = GetAddressFromPrivateKey(privateKey);
+
+ return new KeyPairInfo
{
- return Address.FromBase58(base58String);
- }
-
- public KeyPairInfo GenerateKeyPairInfo()
+ PrivateKey = privateKey,
+ PublicKey = publicKey,
+ Address = address
+ };
+ }
+
+ #region private methods
+
+ private ECKeyPair GetAElfKeyPair(string? privateKeyHex)
+ {
+ var privateKey = ByteArrayHelper.HexStringToByteArray(privateKeyHex);
+ var keyPair = CryptoHelper.FromPrivateKey(privateKey);
+
+ return keyPair;
+ }
+
+ private string GetRequestUrl(string baseUrl, string relativeUrl)
+ {
+ var uri = new Uri(baseUrl + (baseUrl.EndsWith("/") ? "" : "/"));
+ return new Uri(uri, relativeUrl).ToString();
+ }
+
+ private void AssertValidAddress(params string?[] addresses)
+ {
+ try
{
- var keyPair = CryptoHelper.GenerateKeyPair();
- var privateKey = keyPair.PrivateKey.ToHex();
- var publicKey = keyPair.PublicKey.ToHex();
- var address = GetAddressFromPrivateKey(privateKey);
-
- return new KeyPairInfo
+ foreach (var address in addresses)
{
- PrivateKey = privateKey,
- PublicKey = publicKey,
- Address = address
- };
- }
-
- #region private methods
-
- private ECKeyPair GetAElfKeyPair(string? privateKeyHex)
- {
- var privateKey = ByteArrayHelper.HexStringToByteArray(privateKeyHex);
- var keyPair = CryptoHelper.FromPrivateKey(privateKey);
-
- return keyPair;
+ Address.FromBase58(address);
+ }
}
-
- private string GetRequestUrl(string baseUrl, string relativeUrl)
+ catch (Exception)
{
- return new Uri(new Uri(baseUrl + (baseUrl.EndsWith("/") ? "" : "/")), relativeUrl).ToString();
+ throw new AElfClientException(Error.Message[Error.InvalidAddress]);
}
+ }
- private void AssertValidAddress(params string?[] addresses)
+ private void AssertValidHash(params string[] hashes)
+ {
+ try
{
- try
+ foreach (var hash in hashes)
{
- foreach (var address in addresses)
- {
- Address.FromBase58(address);
- }
- }
- catch (Exception)
- {
- throw new AElfClientException(Error.Message[Error.InvalidAddress]);
+ Hash.LoadFromHex(hash);
}
}
-
- private void AssertValidHash(params string[] hashes)
+ catch (Exception)
{
- try
- {
- foreach (var hash in hashes)
- {
- Hash.LoadFromHex(hash);
- }
- }
- catch (Exception)
- {
- throw new AElfClientException(Error.Message[Error.InvalidBlockHash]);
- }
+ throw new AElfClientException(Error.Message[Error.InvalidBlockHash]);
}
+ }
- private void AssertValidTransactionId(params string[] transactionIds)
+ private void AssertValidTransactionId(params string[] transactionIds)
+ {
+ try
{
- try
+ foreach (var transactionId in transactionIds)
{
- foreach (var transactionId in transactionIds)
- {
- Hash.LoadFromHex(transactionId);
- }
- }
- catch (Exception)
- {
- throw new AElfClientException(Error.Message[Error.InvalidTransactionId]);
+ Hash.LoadFromHex(transactionId);
}
}
+ catch (Exception)
+ {
+ throw new AElfClientException(Error.Message[Error.InvalidTransactionId]);
+ }
+ }
- #endregion
+ #endregion
}
\ No newline at end of file
diff --git a/src/AElf.Client/AElfClient.Net.cs b/src/AElf.Client/AElfClient.Net.cs
index 89b2f5b..5b4d4fb 100644
--- a/src/AElf.Client/AElfClient.Net.cs
+++ b/src/AElf.Client/AElfClient.Net.cs
@@ -9,72 +9,72 @@ namespace AElf.Client;
public partial class AElfClient : INetAppService
{
///
- /// Attempt to add a node to the connected network nodes.Input parameter contains the ipAddress of the node.
- ///
- ///
- ///
- ///
- /// Add successfully or not
- public async Task AddPeerAsync(string ipAddress, string userName, string password)
+ /// Attempt to add a node to the connected network nodes.Input parameter contains the ipAddress of the node.
+ ///
+ ///
+ ///
+ ///
+ /// Add successfully or not
+ public async Task AddPeerAsync(string ipAddress, string? userName, string? password)
+ {
+ if (!EndpointHelper.TryParse(ipAddress, out var endpoint))
{
- if (!EndpointHelper.TryParse(ipAddress, out var endpoint))
- {
- return false;
- }
-
- var url = GetRequestUrl(_baseUrl, "api/net/peer");
- var parameters = new Dictionary
- {
- {"address", endpoint?.ToString() ?? AElfClientConstants.LocalEndpoint}
- };
-
- return await _httpService.PostResponseAsync(url, parameters,
- authenticationHeaderValue: GetAuthenticationHeaderValue());
+ return false;
}
- ///
- /// Attempt to remove a node from the connected network nodes by given the ipAddress.
- ///
- ///
- ///
- ///
- /// Delete successfully or not
- public async Task RemovePeerAsync(string ipAddress, string userName, string password)
+ var url = GetRequestUrl(_baseUrl, "api/net/peer");
+ var parameters = new Dictionary
{
- if (!EndpointHelper.TryParse(ipAddress, out var endpoint))
- {
- return false;
- }
+ { "address", endpoint?.ToString() ?? AElfClientConstants.LocalEndpoint },
+ };
- var url = GetRequestUrl(_baseUrl, $"api/net/peer?address={endpoint}");
- return await _httpService.DeleteResponseAsObjectAsync(url,
- authenticationHeaderValue: GetAuthenticationHeaderValue());
- }
+ return await _httpService.PostResponseAsync(url, parameters,
+ authenticationHeaderValue: GetAuthenticationHeaderValue(userName, password));
+ }
- ///
- /// Gets information about the peer nodes of the current node.Optional whether to include metrics.
- ///
- ///
- /// Information about the peer nodes
- public async Task?> GetPeersAsync(bool withMetrics)
+ ///
+ /// Attempt to remove a node from the connected network nodes by given the ipAddress.
+ ///
+ ///
+ ///
+ ///
+ /// Delete successfully or not
+ public async Task RemovePeerAsync(string ipAddress, string? userName, string? password)
+ {
+ if (!EndpointHelper.TryParse(ipAddress, out var endpoint))
{
- var url = GetRequestUrl(_baseUrl, $"api/net/peers?withMetrics={withMetrics}");
- return await _httpService.GetResponseAsync>(url);
+ return false;
}
- ///
- /// Get the node's network information.
- ///
- /// Network information
- public async Task GetNetworkInfoAsync()
- {
- var url = GetRequestUrl(_baseUrl, "api/net/networkInfo");
- return await _httpService.GetResponseAsync(url);
- }
+ var url = GetRequestUrl(_baseUrl, $"api/net/peer?address={endpoint}");
+ return await _httpService.DeleteResponseAsObjectAsync(url,
+ authenticationHeaderValue: GetAuthenticationHeaderValue(userName, password));
+ }
- private AuthenticationHeaderValue GetAuthenticationHeaderValue()
- {
- var byteArray = Encoding.ASCII.GetBytes($"{_userName}:{_password}");
- return new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
- }
+ ///
+ /// Gets information about the peer nodes of the current node.Optional whether to include metrics.
+ ///
+ ///
+ /// Information about the peer nodes
+ public async Task?> GetPeersAsync(bool withMetrics)
+ {
+ var url = GetRequestUrl(_baseUrl, $"api/net/peers?withMetrics={withMetrics}");
+ return await _httpService.GetResponseAsync>(url);
+ }
+
+ ///
+ /// Get the node's network information.
+ ///
+ /// Network information
+ public async Task GetNetworkInfoAsync()
+ {
+ var url = GetRequestUrl(_baseUrl, "api/net/networkInfo");
+ return await _httpService.GetResponseAsync(url);
+ }
+
+ private AuthenticationHeaderValue GetAuthenticationHeaderValue(string? userName, string? password)
+ {
+ var byteArray = Encoding.ASCII.GetBytes($"{userName ?? _userName}:{password ?? _password}");
+ return new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
+ }
}
\ No newline at end of file
diff --git a/src/AElf.Client/AElfClient.Transaction.cs b/src/AElf.Client/AElfClient.Transaction.cs
index d1b6b4a..5afbc16 100644
--- a/src/AElf.Client/AElfClient.Transaction.cs
+++ b/src/AElf.Client/AElfClient.Transaction.cs
@@ -6,160 +6,160 @@ namespace AElf.Client;
public partial class AElfClient : ITransactionAppService
{
///
- /// Get information about the current transaction pool.
- ///
- /// TransactionPoolStatusOutput
- public async Task GetTransactionPoolStatusAsync()
- {
- var url = GetRequestUrl(_baseUrl, "api/blockChain/transactionPoolStatus");
- return await _httpService.GetResponseAsync(url);
- }
+ /// Get information about the current transaction pool.
+ ///
+ /// TransactionPoolStatusOutput
+ public async Task GetTransactionPoolStatusAsync()
+ {
+ var url = GetRequestUrl(_baseUrl, "api/blockChain/transactionPoolStatus");
+ return await _httpService.GetResponseAsync(url);
+ }
- ///
- /// Call a read-only method of a contract.
- ///
- ///
- ///
- public async Task ExecuteTransactionAsync(ExecuteTransactionDto input)
+ ///
+ /// Call a read-only method of a contract.
+ ///
+ ///
+ ///
+ public async Task ExecuteTransactionAsync(ExecuteTransactionDto input)
+ {
+ var url = GetRequestUrl(_baseUrl, "api/blockChain/executeTransaction");
+ var parameters = new Dictionary
{
- var url = GetRequestUrl(_baseUrl, "api/blockChain/executeTransaction");
- var parameters = new Dictionary
- {
- {"RawTransaction", input.RawTransaction}
- };
-
- var result = await _httpService.PostResponseAsync(url, parameters);
+ { "RawTransaction", input.RawTransaction }
+ };
- if (result == null)
- {
- throw new AElfClientException("Failed to execute tx.");
- }
+ var result = await _httpService.PostResponseAsync(url, parameters);
- return result;
- }
-
- ///
- /// Call a method of a contract by given serialized strings.
- ///
- ///
- /// Serialized result
- public async Task ExecuteRawTransactionAsync(ExecuteRawTransactionDto input)
+ if (result == null)
{
- var url = GetRequestUrl(_baseUrl, "api/blockChain/executeRawTransaction");
- var parameters = new Dictionary
- {
- {"RawTransaction", input.RawTransaction},
- {"Signature", input.Signature}
- };
-
- return await _httpService.PostResponseAsync(url, parameters);
+ throw new AElfClientException("Failed to execute tx.");
}
- ///
- /// Creates an unsigned serialized transaction.
- ///
- ///
- /// CreateRawTransactionOutput
- public async Task CreateRawTransactionAsync(CreateRawTransactionInput input)
- {
- var url = GetRequestUrl(_baseUrl, "api/blockChain/rawTransaction");
- var parameters = new Dictionary
- {
- {"From", input.From},
- {"To", input.To},
- {"RefBlockNumber", input.RefBlockNumber.ToString()},
- {"RefBlockHash", input.RefBlockHash},
- {"MethodName", input.MethodName},
- {"Params", input.Params}
- };
-
- return await _httpService.PostResponseAsync(url, parameters);
- }
+ return result;
+ }
- ///
- /// Broadcast a serialized transaction.
- ///
- ///
- /// SendRawTransactionOutput
- public async Task SendRawTransactionAsync(SendRawTransactionInput input)
+ ///
+ /// Call a method of a contract by given serialized strings.
+ ///
+ ///
+ /// Serialized result
+ public async Task ExecuteRawTransactionAsync(ExecuteRawTransactionDto input)
+ {
+ var url = GetRequestUrl(_baseUrl, "api/blockChain/executeRawTransaction");
+ var parameters = new Dictionary
{
- var url = GetRequestUrl(_baseUrl, "api/blockChain/sendRawTransaction");
- var parameters = new Dictionary
- {
- {"Transaction", input.Transaction},
- {"Signature", input.Signature},
- {"ReturnTransaction", input.ReturnTransaction ? "true" : "false"}
- };
- return await _httpService.PostResponseAsync(url, parameters);
- }
+ { "RawTransaction", input.RawTransaction },
+ { "Signature", input.Signature }
+ };
- ///
- /// Broadcast a transaction.
- ///
- ///
- /// TransactionId
- public async Task SendTransactionAsync(SendTransactionInput input)
- {
- var url = GetRequestUrl(_baseUrl, "api/blockChain/sendTransaction");
- var parameters = new Dictionary
- {
- {"RawTransaction", input.RawTransaction}
- };
- return await _httpService.PostResponseAsync(url, parameters);
- }
+ return await _httpService.PostResponseAsync(url, parameters);
+ }
- ///
- /// Broadcast volume transactions.
- ///
- ///
- /// TransactionIds
- public async Task SendTransactionsAsync(SendTransactionsInput input)
+ ///
+ /// Creates an unsigned serialized transaction.
+ ///
+ ///
+ /// CreateRawTransactionOutput
+ public async Task CreateRawTransactionAsync(CreateRawTransactionInput input)
+ {
+ var url = GetRequestUrl(_baseUrl, "api/blockChain/rawTransaction");
+ var parameters = new Dictionary
{
- var url = GetRequestUrl(_baseUrl, "api/blockChain/sendTransactions");
- var parameters = new Dictionary
- {
- {"RawTransactions", input.RawTransactions}
- };
- return await _httpService.PostResponseAsync(url, parameters);
- }
+ { "From", input.From },
+ { "To", input.To },
+ { "RefBlockNumber", input.RefBlockNumber.ToString() },
+ { "RefBlockHash", input.RefBlockHash },
+ { "MethodName", input.MethodName },
+ { "Params", input.Params }
+ };
- ///
- /// Gets the result of transaction execution by the given transactionId.
- ///
- ///
- /// TransactionResultDto
- public async Task GetTransactionResultAsync(string transactionId)
+ return await _httpService.PostResponseAsync(url, parameters);
+ }
+
+ ///
+ /// Broadcast a serialized transaction.
+ ///
+ ///
+ /// SendRawTransactionOutput
+ public async Task SendRawTransactionAsync(SendRawTransactionInput input)
+ {
+ var url = GetRequestUrl(_baseUrl, "api/blockChain/sendRawTransaction");
+ var parameters = new Dictionary
{
- AssertValidTransactionId(transactionId);
- var url = GetRequestUrl(_baseUrl, $"api/blockChain/transactionResult?transactionId={transactionId}");
- return await _httpService.GetResponseAsync(url);
- }
+ { "Transaction", input.Transaction },
+ { "Signature", input.Signature },
+ { "ReturnTransaction", input.ReturnTransaction ? "true" : "false" }
+ };
+ return await _httpService.PostResponseAsync(url, parameters);
+ }
- ///
- /// Get results of multiple transactions by specified blockHash and the offset.
- ///
- ///
- ///
- ///
- /// TransactionResultDtos
- public async Task?> GetTransactionResultsAsync(string blockHash, int offset = 0,
- int limit = 10)
+ ///
+ /// Broadcast a transaction.
+ ///
+ ///
+ /// TransactionId
+ public async Task SendTransactionAsync(SendTransactionInput input)
+ {
+ var url = GetRequestUrl(_baseUrl, "api/blockChain/sendTransaction");
+ var parameters = new Dictionary
{
- AssertValidHash(blockHash);
- var url = GetRequestUrl(_baseUrl,
- $"api/blockChain/transactionResults?blockHash={blockHash}&offset={offset}&limit={limit}");
- return await _httpService.GetResponseAsync>(url);
- }
+ { "RawTransaction", input.RawTransaction }
+ };
+ return await _httpService.PostResponseAsync(url, parameters);
+ }
- ///
- /// Get merkle path of a transaction.
- ///
- ///
- /// MerklePathDto
- public async Task GetMerklePathByTransactionIdAsync(string transactionId)
+ ///
+ /// Broadcast volume transactions.
+ ///
+ ///
+ /// TransactionIds
+ public async Task SendTransactionsAsync(SendTransactionsInput input)
+ {
+ var url = GetRequestUrl(_baseUrl, "api/blockChain/sendTransactions");
+ var parameters = new Dictionary
{
- AssertValidTransactionId(transactionId);
- var url = GetRequestUrl(_baseUrl, $"api/blockChain/merklePathByTransactionId?transactionId={transactionId}");
- return await _httpService.GetResponseAsync(url);
- }
+ { "RawTransactions", input.RawTransactions }
+ };
+ return await _httpService.PostResponseAsync(url, parameters);
+ }
+
+ ///
+ /// Gets the result of transaction execution by the given transactionId.
+ ///
+ ///
+ /// TransactionResultDto
+ public async Task GetTransactionResultAsync(string transactionId)
+ {
+ AssertValidTransactionId(transactionId);
+ var url = GetRequestUrl(_baseUrl, $"api/blockChain/transactionResult?transactionId={transactionId}");
+ return await _httpService.GetResponseAsync(url);
+ }
+
+ ///
+ /// Get results of multiple transactions by specified blockHash and the offset.
+ ///
+ ///
+ ///
+ ///
+ /// TransactionResultDtos
+ public async Task?> GetTransactionResultsAsync(string blockHash, int offset = 0,
+ int limit = 10)
+ {
+ AssertValidHash(blockHash);
+ var url = GetRequestUrl(_baseUrl,
+ $"api/blockChain/transactionResults?blockHash={blockHash}&offset={offset}&limit={limit}");
+ return await _httpService.GetResponseAsync>(url);
+ }
+
+ ///
+ /// Get merkle path of a transaction.
+ ///
+ ///
+ /// MerklePathDto
+ public async Task GetMerklePathByTransactionIdAsync(string transactionId)
+ {
+ AssertValidTransactionId(transactionId);
+ var url = GetRequestUrl(_baseUrl, $"api/blockChain/merklePathByTransactionId?transactionId={transactionId}");
+ return await _httpService.GetResponseAsync(url);
+ }
}
\ No newline at end of file
diff --git a/src/AElf.Client/AElfClient.cs b/src/AElf.Client/AElfClient.cs
index a45bb29..f5cd32d 100644
--- a/src/AElf.Client/AElfClient.cs
+++ b/src/AElf.Client/AElfClient.cs
@@ -1,18 +1,19 @@
-using System.Text.Json;
-using AElf.Client.Service;
+using AElf.Client.Services;
namespace AElf.Client;
public partial class AElfClient : IDisposable
{
private readonly IHttpService _httpService;
+ // aelf node endpoint.
private readonly string _baseUrl;
- private readonly string _userName;
- private readonly string _password;
+ private string? _userName;
+ private string? _password;
- public AElfClient(string baseUrl, int timeOut = 60, string userName = null, string password = null)
+ public AElfClient(string baseUrl, int timeOut = 60, string? userName = null, string? password = null,
+ bool useCamelCase = false)
{
- _httpService = new HttpService(timeOut);
+ _httpService = new HttpService(timeOut, useCamelCase);
_baseUrl = baseUrl;
_userName = userName;
_password = password;
diff --git a/src/AElf.Client/AElfClientBuilder.cs b/src/AElf.Client/AElfClientBuilder.cs
index c2a04fe..91444fd 100644
--- a/src/AElf.Client/AElfClientBuilder.cs
+++ b/src/AElf.Client/AElfClientBuilder.cs
@@ -5,8 +5,10 @@ public sealed class AElfClientBuilder
private string NodeEndpoint { get; set; }
private int Timeout { get; set; }
- private string UserName { get; set; }
- private string Password { get; set; }
+ private string? UserName { get; set; }
+ private string? Password { get; set; }
+
+ private bool IsUseCamelCase { get; set; }
public AElfClientBuilder()
{
@@ -27,14 +29,14 @@ public AElfClientBuilder UsePublicEndpoint(EndpointType endpointType)
case EndpointType.MainNetMainChain:
NodeEndpoint = AElfClientConstants.MainNetMainChain;
break;
- case EndpointType.MainNetSidechain:
- NodeEndpoint = AElfClientConstants.MainNetSidechain;
+ case EndpointType.MainNetSideChain1:
+ NodeEndpoint = AElfClientConstants.MainNetSideChain1;
break;
case EndpointType.TestNetMainChain:
NodeEndpoint = AElfClientConstants.TestNetMainChain;
break;
- case EndpointType.TestNetSidechain:
- NodeEndpoint = AElfClientConstants.TestNetSidechain;
+ case EndpointType.TestNetSideChain2:
+ NodeEndpoint = AElfClientConstants.TestNetSideChain2;
break;
case EndpointType.Local:
default:
@@ -51,15 +53,21 @@ public AElfClientBuilder SetHttpTimeout(int timeout)
return this;
}
- public AElfClientBuilder ManagePeerInfo(string userName, string password)
+ public AElfClientBuilder ManagePeerInfo(string? userName, string? password)
{
UserName = userName;
Password = password;
return this;
}
+ public AElfClientBuilder UseCamelCase(bool isUseCamelCase)
+ {
+ IsUseCamelCase = isUseCamelCase;
+ return this;
+ }
+
public AElfClient Build()
{
- return new AElfClient(NodeEndpoint, Timeout, UserName, Password);
+ return new AElfClient(NodeEndpoint, Timeout, UserName, Password, IsUseCamelCase);
}
}
\ No newline at end of file
diff --git a/src/AElf.Client/AElfClientConstants.cs b/src/AElf.Client/AElfClientConstants.cs
index 6c1efc9..b55f7e8 100644
--- a/src/AElf.Client/AElfClientConstants.cs
+++ b/src/AElf.Client/AElfClientConstants.cs
@@ -3,11 +3,13 @@ namespace AElf.Client;
public class AElfClientConstants
{
public const string DefaultPrivateKey = "09da44778f8db2e602fb484334f37df19e221c84c4582ce5b7770ccfbc3ddbef";
- public const string LocalEndpoint = "http://127.0.0.1:1235";
+ public const string LocalEndpoint = "http://127.0.0.1:1726";
public const string MainNetMainChain = "https://aelf-public-node.aelf.io";
- public const string MainNetSidechain = "https://tdvv-public-node.aelf.io";
+ public const string MainNetSideChain1 = "https://tdvv-public-node.aelf.io";
public const string TestNetMainChain = "https://aelf-test-node.aelf.io";
- public const string TestNetSidechain = "https://tdvv-test-node.aelf.io";
+ public const string TestNetSideChain1 = "https://tdvv-test-node.aelf.io";
+ public const string TestNetSideChain2 = "https://tdvw-test-node.aelf.io";
public const int MainChainId = 9992731;
- public const int SidechainId = 9992731;
+ public const int SideChainId1 = 1866392;
+ public const int SideChainId2 = 1931928;
}
\ No newline at end of file
diff --git a/src/AElf.Client/Dto/BlockDto.cs b/src/AElf.Client/Dto/BlockDto.cs
index 2c25367..a155653 100644
--- a/src/AElf.Client/Dto/BlockDto.cs
+++ b/src/AElf.Client/Dto/BlockDto.cs
@@ -7,4 +7,6 @@ public class BlockDto
public BlockHeaderDto Header { get; set; }
public BlockBodyDto Body { get; set; }
+
+ public int BlockSize { get; set; }
}
\ No newline at end of file
diff --git a/src/AElf.Client/Dto/ChainStatusDto.cs b/src/AElf.Client/Dto/ChainStatusDto.cs
index 2cb6580..45feb0d 100644
--- a/src/AElf.Client/Dto/ChainStatusDto.cs
+++ b/src/AElf.Client/Dto/ChainStatusDto.cs
@@ -1,26 +1,28 @@
+using System.Text.Json.Serialization;
+
namespace AElf.Client.Dto;
public class ChainStatusDto
{
public string ChainId { get; set; }
-
- public Dictionary Branches { get; set; }
-
- public Dictionary NotLinkedBlocks { get; set; }
-
+
+ public Dictionary Branches { get; set; }
+
+ public Dictionary NotLinkedBlocks { get; set; }
+
public long LongestChainHeight { get; set; }
-
+
public string LongestChainHash { get; set; }
public string GenesisBlockHash { get; set; }
-
+
public string GenesisContractAddress { get; set; }
-
+
public string LastIrreversibleBlockHash { get; set; }
-
+
public long LastIrreversibleBlockHeight { get; set; }
-
+
public string BestChainHash { get; set; }
-
+
public long BestChainHeight { get; set; }
}
\ No newline at end of file
diff --git a/src/AElf.Client/Dto/MerklePathDto.cs b/src/AElf.Client/Dto/MerklePathDto.cs
index ee0f9d1..dbd8994 100644
--- a/src/AElf.Client/Dto/MerklePathDto.cs
+++ b/src/AElf.Client/Dto/MerklePathDto.cs
@@ -2,7 +2,7 @@ namespace AElf.Client.Dto;
public class MerklePathDto
{
- public List MerklePathNodes;
+ public List MerklePathNodes { get; set; }
}
public class MerklePathNodeDto
diff --git a/src/AElf.Client/Dto/PeerDto.cs b/src/AElf.Client/Dto/PeerDto.cs
index 411c2df..d7ba842 100644
--- a/src/AElf.Client/Dto/PeerDto.cs
+++ b/src/AElf.Client/Dto/PeerDto.cs
@@ -1,3 +1,5 @@
+using Google.Protobuf.WellKnownTypes;
+
namespace AElf.Client.Dto;
public class PeerDto
@@ -18,5 +20,5 @@ public class RequestMetric
public long RoundTripTime { get; set; }
public string MethodName { get; set; }
public string Info { get; set; }
- public string RequestTime { get; set; }
+ public Timestamp RequestTime { get; set; }
}
\ No newline at end of file
diff --git a/src/AElf.Client/Dto/TransactionResultDto.cs b/src/AElf.Client/Dto/TransactionResultDto.cs
index 30ff3fa..815aa47 100644
--- a/src/AElf.Client/Dto/TransactionResultDto.cs
+++ b/src/AElf.Client/Dto/TransactionResultDto.cs
@@ -3,20 +3,22 @@ namespace AElf.Client.Dto;
public class TransactionResultDto
{
public string TransactionId { get; set; }
-
+
public string Status { get; set; }
-
+
public LogEventDto[] Logs { get; set; }
-
+
public string Bloom { get; set; }
-
+
public long BlockNumber { get; set; }
-
+
public string BlockHash { get; set; }
-
+
public TransactionDto Transaction { get; set; }
-
+
public string ReturnValue { get; set; }
public string Error { get; set; }
+
+ public int TransactionSize { get; set; }
}
\ No newline at end of file
diff --git a/src/AElf.Client/EndpointType.cs b/src/AElf.Client/EndpointType.cs
index 0b132fa..43011e0 100644
--- a/src/AElf.Client/EndpointType.cs
+++ b/src/AElf.Client/EndpointType.cs
@@ -3,8 +3,8 @@ namespace AElf.Client;
public enum EndpointType
{
MainNetMainChain,
- MainNetSidechain,
+ MainNetSideChain1,
TestNetMainChain,
- TestNetSidechain,
+ TestNetSideChain2,
Local
}
\ No newline at end of file
diff --git a/src/AElf.Client/Services/HttpService.cs b/src/AElf.Client/Services/HttpService.cs
index 74bbdde..388d59c 100644
--- a/src/AElf.Client/Services/HttpService.cs
+++ b/src/AElf.Client/Services/HttpService.cs
@@ -1,13 +1,9 @@
-using System;
-using System.Collections.Generic;
using System.Net;
-using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
-using System.Threading.Tasks;
-namespace AElf.Client.Service;
+namespace AElf.Client.Services;
public interface IHttpService
{
@@ -20,16 +16,18 @@ public interface IHttpService
Task DeleteResponseAsObjectAsync(string url, string? version = null,
HttpStatusCode expectedStatusCode = HttpStatusCode.OK,
- AuthenticationHeaderValue authenticationHeaderValue = null);
+ AuthenticationHeaderValue? authenticationHeaderValue = null);
}
public class HttpService : IHttpService
{
- private HttpClient Client { get; set; }
+ private readonly bool _useCamelCase;
+ private HttpClient? Client { get; set; }
private int TimeoutSeconds { get; }
- public HttpService(int timeoutSeconds)
+ public HttpService(int timeoutSeconds, bool useCamelCase = false)
{
+ _useCamelCase = useCamelCase;
TimeoutSeconds = timeoutSeconds;
}
@@ -46,7 +44,13 @@ public HttpService(int timeoutSeconds)
{
var response = await GetResponseAsync(url, version, expectedStatusCode);
var stream = await response.Content.ReadAsStreamAsync();
- return await JsonSerializer.DeserializeAsync(stream);
+ var jsonSerializerOptions = _useCamelCase
+ ? new JsonSerializerOptions
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase
+ }
+ : new JsonSerializerOptions();
+ return await JsonSerializer.DeserializeAsync(stream, jsonSerializerOptions);
}
///
@@ -67,7 +71,13 @@ public HttpService(int timeoutSeconds)
var response = await PostResponseAsync(url, parameters, version, true, expectedStatusCode,
authenticationHeaderValue);
var stream = await response.Content.ReadAsStreamAsync();
- return await JsonSerializer.DeserializeAsync(stream);
+ var jsonSerializerOptions = _useCamelCase
+ ? new JsonSerializerOptions
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase
+ }
+ : new JsonSerializerOptions();
+ return await JsonSerializer.DeserializeAsync(stream, jsonSerializerOptions);
}
///
@@ -76,16 +86,23 @@ public HttpService(int timeoutSeconds)
///
///
///
+ ///
///
///
///
public async Task DeleteResponseAsObjectAsync(string url, string? version = null,
HttpStatusCode expectedStatusCode = HttpStatusCode.OK,
- AuthenticationHeaderValue authenticationHeaderValue = null)
+ AuthenticationHeaderValue? authenticationHeaderValue = null)
{
var response = await DeleteResponseAsync(url, version, expectedStatusCode, authenticationHeaderValue);
var stream = await response.Content.ReadAsStreamAsync();
- return await JsonSerializer.DeserializeAsync(stream);
+ var jsonSerializerOptions = _useCamelCase
+ ? new JsonSerializerOptions
+ {
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase
+ }
+ : new JsonSerializerOptions();
+ return await JsonSerializer.DeserializeAsync(stream, jsonSerializerOptions);
}
#region GetResponse
@@ -162,7 +179,7 @@ private async Task PostResponseAsync(string url,
private async Task DeleteResponseAsStringAsync(string url, string? version = null,
HttpStatusCode expectedStatusCode = HttpStatusCode.OK,
- AuthenticationHeaderValue authenticationHeaderValue = null)
+ AuthenticationHeaderValue? authenticationHeaderValue = null)
{
var response = await DeleteResponseAsync(url, version, expectedStatusCode, authenticationHeaderValue);
return await response.Content.ReadAsStringAsync();
@@ -170,7 +187,7 @@ private async Task DeleteResponseAsStringAsync(string url, string? versi
private async Task DeleteResponseAsync(string url, string? version = null,
HttpStatusCode expectedStatusCode = HttpStatusCode.OK,
- AuthenticationHeaderValue authenticationHeaderValue = null)
+ AuthenticationHeaderValue? authenticationHeaderValue = null)
{
version = !string.IsNullOrWhiteSpace(version) ? $";v={version}" : string.Empty;
var client = GetHttpClient(version);
diff --git a/src/AElf.Client/Services/IChainAppService.cs b/src/AElf.Client/Services/IChainAppService.cs
index 48d9b61..1685b1d 100644
--- a/src/AElf.Client/Services/IChainAppService.cs
+++ b/src/AElf.Client/Services/IChainAppService.cs
@@ -1,5 +1,4 @@
using AElf.Client.Dto;
-using AElf.Kernel;
namespace AElf.Client;
diff --git a/src/AElf.Client/TransactionBuilder.cs b/src/AElf.Client/TransactionBuilder.cs
index beb357f..2b352b6 100644
--- a/src/AElf.Client/TransactionBuilder.cs
+++ b/src/AElf.Client/TransactionBuilder.cs
@@ -1,5 +1,6 @@
using AElf.Cryptography;
using Google.Protobuf;
+using Volo.Abp.Threading;
namespace AElf.Client;
@@ -8,9 +9,9 @@ public class TransactionBuilder
private readonly AElfClient _aelfClient;
private byte[] PrivateKey { get; set; }
- private string ContractAddress { get; set; }
- private string MethodName { get; set; }
- private IMessage Parameter { get; set; }
+ private string? ContractAddress { get; set; }
+ private string? MethodName { get; set; }
+ private IMessage? Parameter { get; set; }
public TransactionBuilder(AElfClient aelfClient)
{
@@ -26,8 +27,8 @@ public TransactionBuilder UsePrivateKey(byte[] privateKey)
public TransactionBuilder UseSystemContract(string systemContractName)
{
- ContractAddress = _aelfClient.GetContractAddressByNameAsync(HashHelper.ComputeFrom(systemContractName)).Result
- .ToBase58();
+ ContractAddress = AsyncHelper.RunSync(async () =>
+ (await _aelfClient.GetContractAddressByNameAsync(HashHelper.ComputeFrom(systemContractName))).ToBase58());
return this;
}
diff --git a/test/AElf.Client.Test/AElf.Client.Test.csproj b/test/AElf.Client.Test/AElf.Client.Test.csproj
index f6a8729..647ea1f 100644
--- a/test/AElf.Client.Test/AElf.Client.Test.csproj
+++ b/test/AElf.Client.Test/AElf.Client.Test.csproj
@@ -3,18 +3,29 @@
net6.0
false
+ enable
+
+ false
+
-
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
-
+
diff --git a/test/AElf.Client.Test/BasicTests.cs b/test/AElf.Client.Test/BasicTests.cs
new file mode 100644
index 0000000..a3e3dec
--- /dev/null
+++ b/test/AElf.Client.Test/BasicTests.cs
@@ -0,0 +1,15 @@
+using AElf.Types;
+using Shouldly;
+
+namespace AElf.Client.Test;
+
+public class BasicTests
+{
+ [Theory]
+ [InlineData("04c1b4a75fd9ba37e0a84b9916e517e9c591c5b9efacabf1feb1a3d34f38920a250454dc9dce0f811956d210804c904959be96a75a9d9b1410aa25f7d9e1b6f69c")]
+ public void PubkeyToAddressTest(string pubkey)
+ {
+ var address = Address.FromPublicKey(ByteArrayHelper.HexStringToByteArray(pubkey));
+ address.ShouldNotBeNull();
+ }
+}
\ No newline at end of file
diff --git a/test/AElf.Client.Test/ClientTest.cs b/test/AElf.Client.Test/ClientTest.cs
index 4127c7f..888d971 100644
--- a/test/AElf.Client.Test/ClientTest.cs
+++ b/test/AElf.Client.Test/ClientTest.cs
@@ -8,7 +8,7 @@
using AElf.Types;
using AElf.Client.Dto;
using AElf.Client.Extensions;
-using AElf.Client.Service;
+using AElf.Client.Services;
using AElf.Contracts.MultiToken;
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
@@ -25,7 +25,7 @@ namespace AElf.Client.Test;
public class ClientTest
{
- private const string BaseUrl = "http://192.168.196.116:8000";
+ private const string BaseUrl = "https://tdvw-test-node.aelf.io";
private string _genesisAddress;
private string GenesisAddress => GetGenesisContractAddress();
@@ -84,7 +84,7 @@ public async Task GetBlock_Test()
public async Task GetBlockByHeight_Failed_Test()
{
const int timeOut = 60;
- var httpService = new HttpService(timeOut);
+ var httpService = new HttpService(timeOut, false);
const int heightNotExist = int.MaxValue;
var errorResponse = await httpService.GetResponseAsync(
$"{BaseUrl}/api/blockChain/blockByHeight?blockHeight={heightNotExist}&includeTransactions=false",
@@ -160,6 +160,15 @@ public async Task GetPeers_Test()
var peersInfo = JsonConvert.SerializeObject(peers, Formatting.Indented);
_testOutputHelper.WriteLine(peersInfo);
}
+
+ [Fact]
+ public async Task GetPeersWithMetrics_Test()
+ {
+ var peers = await Client.GetPeersAsync(true);
+ Assert.True(peers != null);
+ var peersInfo = JsonConvert.SerializeObject(peers, Formatting.Indented);
+ _testOutputHelper.WriteLine(peersInfo);
+ }
[Fact]
public async Task GetNetworkInfo_Test()
diff --git a/test/AElf.Client.Test/Usings.cs b/test/AElf.Client.Test/Usings.cs
new file mode 100644
index 0000000..8c927eb
--- /dev/null
+++ b/test/AElf.Client.Test/Usings.cs
@@ -0,0 +1 @@
+global using Xunit;
\ No newline at end of file
diff --git a/test/AElf.Client.TestBase/AElf.Client.TestBase.csproj b/test/AElf.Client.TestBase/AElf.Client.TestBase.csproj
new file mode 100644
index 0000000..866a363
--- /dev/null
+++ b/test/AElf.Client.TestBase/AElf.Client.TestBase.csproj
@@ -0,0 +1,44 @@
+
+
+
+ net6.0
+ enable
+ enable
+ false
+
+
+
+
+
+ PreserveNewest
+ true
+ PreserveNewest
+
+
+
+ PreserveNewest
+ Always
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
diff --git a/test/AElf.Client.TestBase/AElfClientAbpTestBase.cs b/test/AElf.Client.TestBase/AElfClientAbpTestBase.cs
new file mode 100644
index 0000000..6640b9d
--- /dev/null
+++ b/test/AElf.Client.TestBase/AElfClientAbpTestBase.cs
@@ -0,0 +1,24 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp;
+using Volo.Abp.Modularity;
+using Volo.Abp.Testing;
+
+namespace AElf.Client.TestBase;
+
+public abstract class AElfClientAbpTestBase : AbpIntegratedTest
+ where TStartupModule : IAbpModule
+{
+ protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
+ {
+ options.UseAutofac();
+ }
+
+ protected override void BeforeAddApplication(IServiceCollection services)
+ {
+ var builder = new ConfigurationBuilder();
+ builder.AddJsonFile("appsettings.json", false);
+ builder.AddJsonFile("appsettings.secrets.json", true);
+ services.ReplaceConfiguration(builder.Build());
+ }
+}
\ No newline at end of file
diff --git a/test/AElf.Client.TestBase/AElfClientAbpTestBaseModule.cs b/test/AElf.Client.TestBase/AElfClientAbpTestBaseModule.cs
new file mode 100644
index 0000000..9f9adb7
--- /dev/null
+++ b/test/AElf.Client.TestBase/AElfClientAbpTestBaseModule.cs
@@ -0,0 +1,14 @@
+using Volo.Abp;
+using Volo.Abp.Autofac;
+using Volo.Abp.Modularity;
+
+namespace AElf.Client.TestBase;
+
+[DependsOn(
+ typeof(AbpAutofacModule),
+ typeof(AbpTestBaseModule)
+)]
+public class AElfClientAbpTestBaseModule : AbpModule
+{
+
+}
\ No newline at end of file
diff --git a/test/AElf.Client.TestBase/IgnoreOnCIFact.cs b/test/AElf.Client.TestBase/IgnoreOnCIFact.cs
new file mode 100644
index 0000000..08a9df4
--- /dev/null
+++ b/test/AElf.Client.TestBase/IgnoreOnCIFact.cs
@@ -0,0 +1,14 @@
+namespace AElf.Client.TestBase;
+
+public sealed class IgnoreOnCIFact : FactAttribute
+{
+ public IgnoreOnCIFact()
+ {
+ if (IsOnCI()) Skip = "Ignore on CI running to save execution time.";
+ }
+
+ private static bool IsOnCI()
+ {
+ return Environment.GetEnvironmentVariable("CI_TEST") != null;
+ }
+}
\ No newline at end of file
diff --git a/test/AElf.Client.TestBase/IgnoreOnCITheory.cs b/test/AElf.Client.TestBase/IgnoreOnCITheory.cs
new file mode 100644
index 0000000..4378f6f
--- /dev/null
+++ b/test/AElf.Client.TestBase/IgnoreOnCITheory.cs
@@ -0,0 +1,14 @@
+namespace AElf.Client.TestBase;
+
+public sealed class IgnoreOnCITheory : TheoryAttribute
+{
+ public IgnoreOnCITheory()
+ {
+ if (IsOnCI()) Skip = "Ignore on CI running to save execution time.";
+ }
+
+ private static bool IsOnCI()
+ {
+ return Environment.GetEnvironmentVariable("CI_TEST") != null;
+ }
+}
\ No newline at end of file
diff --git a/test/AElf.Client.TestBase/Usings.cs b/test/AElf.Client.TestBase/Usings.cs
new file mode 100644
index 0000000..8c927eb
--- /dev/null
+++ b/test/AElf.Client.TestBase/Usings.cs
@@ -0,0 +1 @@
+global using Xunit;
\ No newline at end of file
diff --git a/test/AElf.Client.TestBase/appsettings.json b/test/AElf.Client.TestBase/appsettings.json
new file mode 100644
index 0000000..6bd9fdb
--- /dev/null
+++ b/test/AElf.Client.TestBase/appsettings.json
@@ -0,0 +1,60 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Debug",
+ "System": "Information",
+ "Microsoft": "Information"
+ }
+ },
+ "AElfClient": {
+ "ClientConfigList": [
+ {
+ "Alias": "Example",
+ "Endpoint": "http://192.168.0.31:6800",
+ "UserName": "",
+ "Password": "",
+ "Timeout": 100
+ }
+ ]
+ },
+ "AElfAccount": {
+ "KeyDirectory": "",
+ "AccountConfigList": [
+ {
+ "Alias": "Ean",
+ "PrivateKey": "8cc296e44d9e8881942e75a21ebc116ed3f29e39e0eaace1c92dc21e86d215c3",
+ "Address": "2AiXjNszZwUMdonm2RYb3GsB3aLUU3hkD1fxoazMwqPAamerLQ",
+ "Password": "aelftest"
+ },
+ {
+ "Alias": "Test1",
+ "Address": "215tht8WyakoxNK4SvsR132jChydxE27RtJN8HSk1UXxuDQnmM",
+ "Password": "aelftest"
+ },
+ {
+ "Alias": "Test2",
+ "PrivateKey": "5e2f12d13e4527ad1128e07db00f1614ec6b8b51662e68d4fdb42125ab384195"
+ },
+ {
+ "Alias": "eanz",
+ "Address": "2HeW7S9HZrbRJZeivMppUuUY3djhWdfVnP5zrDsz8wqq6hKMfT",
+ "Password": "zhaoyiqi"
+ }
+ ]
+ },
+ "AElfContract": {
+ "ContractDirectory": "",
+ "ContractAddressList": {
+ "BridgeContract": "2RHf2fxsnEaM3wb6N1yGqPupNZbcCY98LgWbGSFWmWzgEs5Sjo",
+ "GenesisContract": "2UKQnHcQvhBT6X6ULtfnuh3b9PVRvVMEroHHkcK4YfcoH1Z1x2",
+ "NFTContract": "2ZpYFeE4yWjrcKLBoj1iwbfYnbo9hK7exvfGTdqcq77QSxpzNH"
+ }
+ },
+ "AElfClientConfig": {
+ "ClientAlias": "MainNetMainChain",
+ "MainChainClientAlias": "TestNetMainChain",
+ "SideChainClientAlias": "TestNetSideChain2",
+ "AccountAlias": "eanz",
+ "CamelCase": false
+ }
+}
\ No newline at end of file
diff --git a/test/AElf.Client.TestBase/appsettings.secrets.json b/test/AElf.Client.TestBase/appsettings.secrets.json
new file mode 100644
index 0000000..8e6b25d
--- /dev/null
+++ b/test/AElf.Client.TestBase/appsettings.secrets.json
@@ -0,0 +1,12 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Debug",
+ "System": "Information",
+ "Microsoft": "Information"
+ }
+ },
+ "AElfMinerAccount": {
+ "DefaultPassword": ""
+ }
+}
\ No newline at end of file