diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..48a07ae --- /dev/null +++ b/.gitignore @@ -0,0 +1,261 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc diff --git a/NeoContract.sln b/NeoContract.sln new file mode 100644 index 0000000..ab8795c --- /dev/null +++ b/NeoContract.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.2035 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SGAS", "NeoContract\SGAS.csproj", "{15DFB6B6-A57D-4A26-A5B7-EA1B2D102E20}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools", "Tools\Tools.csproj", "{A4F2D281-A2E9-4950-AA18-098BF614FD6C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SGAS.UnitTests", "SGAS.UnitTests\SGAS.UnitTests.csproj", "{5C287CB0-FC56-482A-8C91-DB83B60C9B70}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {15DFB6B6-A57D-4A26-A5B7-EA1B2D102E20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {15DFB6B6-A57D-4A26-A5B7-EA1B2D102E20}.Debug|Any CPU.Build.0 = Debug|Any CPU + {15DFB6B6-A57D-4A26-A5B7-EA1B2D102E20}.Release|Any CPU.ActiveCfg = Release|Any CPU + {15DFB6B6-A57D-4A26-A5B7-EA1B2D102E20}.Release|Any CPU.Build.0 = Release|Any CPU + {A4F2D281-A2E9-4950-AA18-098BF614FD6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A4F2D281-A2E9-4950-AA18-098BF614FD6C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A4F2D281-A2E9-4950-AA18-098BF614FD6C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A4F2D281-A2E9-4950-AA18-098BF614FD6C}.Release|Any CPU.Build.0 = Release|Any CPU + {5C287CB0-FC56-482A-8C91-DB83B60C9B70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5C287CB0-FC56-482A-8C91-DB83B60C9B70}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5C287CB0-FC56-482A-8C91-DB83B60C9B70}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5C287CB0-FC56-482A-8C91-DB83B60C9B70}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {CFA1CA3D-396C-4D4F-B1BC-E7B18DC9A5FB} + EndGlobalSection +EndGlobal diff --git a/NeoContract/Neo.ConvertTask.dll b/NeoContract/Neo.ConvertTask.dll new file mode 100644 index 0000000..2de7c65 Binary files /dev/null and b/NeoContract/Neo.ConvertTask.dll differ diff --git a/NeoContract/Neo.SmartContract.Framework.dll b/NeoContract/Neo.SmartContract.Framework.dll new file mode 100644 index 0000000..66491b7 Binary files /dev/null and b/NeoContract/Neo.SmartContract.Framework.dll differ diff --git a/NeoContract/Properties/AssemblyInfo.cs b/NeoContract/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d7e9af2 --- /dev/null +++ b/NeoContract/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NeoContract5")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("NeoContract5")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("15dfb6b6-a57d-4a26-a5b7-ea1b2d102e20")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/NeoContract/SGAS.cs b/NeoContract/SGAS.cs new file mode 100644 index 0000000..8b41715 --- /dev/null +++ b/NeoContract/SGAS.cs @@ -0,0 +1,350 @@ +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Services.Neo; +using Neo.SmartContract.Framework.Services.System; +using Helper = Neo.SmartContract.Framework.Helper; +using System.ComponentModel; +using System.Numerics; +using System; + +namespace SGAS +{ + public class SGAS : SmartContract + { + [DisplayName("transfer")] + public static event deleTransfer Transferred; + public delegate void deleTransfer(byte[] from, byte[] to, BigInteger value); + + [DisplayName("refund")] + public static event deleRefundTarget Refunded; + public delegate void deleRefundTarget(byte[] txid, byte[] who); + + private static readonly byte[] AssetId = Helper.HexToBytes("e72d286979ee6cb1b7e65dfddfb2e384100b8d148e7758de42e4168b71792c60"); //GAS ID, littleEndian + + //StorageMap contract, key: "totalSupply" + //StorageMap refund, key: txHash + //StorageMap asset, key: account + //StorageMap txInfo, key: txHash + + public static object Main(string method, object[] args) + { + if (Runtime.Trigger == TriggerType.Verification) + { + var tx = ExecutionEngine.ScriptContainer as Transaction; + var inputs = tx.GetInputs(); + var outputs = tx.GetOutputs(); + //Check if the input has been marked + foreach (var input in inputs) + { + if (input.PrevIndex == 0)//If UTXO n is 0, it is possible to be a marker UTXO + { + StorageMap refund = Storage.CurrentContext.CreateMap(nameof(refund)); + var refundMan = refund.Get(input.PrevHash); //0.1 + //If the input that is marked for refund + if (refundMan.Length > 0) + { + //Only one input and one output is allowed in refund + if (inputs.Length != 1 || outputs.Length != 1) + return false; + return outputs[0].ScriptHash.AsBigInteger() == refundMan.AsBigInteger(); + } + } + } + var currentHash = ExecutionEngine.ExecutingScriptHash; + //If all the inputs are not marked for refund + BigInteger inputAmount = 0; + foreach (var refe in tx.GetReferences()) + { + if (refe.AssetId.AsBigInteger() != AssetId.AsBigInteger()) + return false;//Not allowed to operate assets other than GAS + + if (refe.ScriptHash.AsBigInteger() == currentHash.AsBigInteger()) + inputAmount += refe.Value; + } + //Check that there is no money left this contract + BigInteger outputAmount = 0; + foreach (var output in outputs) + { + if (output.ScriptHash.AsBigInteger() == currentHash.AsBigInteger()) + outputAmount += output.Value; + } + return outputAmount == inputAmount; + } + else if (Runtime.Trigger == TriggerType.Application) + { + var callscript = ExecutionEngine.CallingScriptHash; + + if (method == "balanceOf") return BalanceOf((byte[])args[0]); + + if (method == "decimals") return Decimals(); + + if (method == "getRefundTarget") return GetRefundTarget((byte[])args[0]); + + if (method == "getTxInfo") return GetTxInfo((byte[])args[0]); + + if (method == "mintTokens") return MintTokens(); + + if (method == "name") return Name(); + + if (method == "refund") return Refund((byte[])args[0]); + + if (method == "symbol") return Symbol(); + + if (method == "supportedStandards") return SupportedStandards(); + + if (method == "totalSupply") return TotalSupply(); + + if (method == "transfer") return Transfer((byte[])args[0], (byte[])args[1], (BigInteger)args[2], callscript); + + if (method == "transferAPP") return TransferAPP((byte[])args[0], (byte[])args[1], (BigInteger)args[2], callscript); + } + else if (Runtime.Trigger == TriggerType.VerificationR) //Backward compatibility, refusing to accept other assets + { + var currentHash = ExecutionEngine.ExecutingScriptHash; + var tx = ExecutionEngine.ScriptContainer as Transaction; + foreach (var output in tx.GetOutputs()) + { + if (output.ScriptHash == currentHash && output.AssetId.AsBigInteger() != AssetId.AsBigInteger()) + return false; + } + return true; + } + return false; + } + + [DisplayName("balanceOf")] + public static BigInteger BalanceOf(byte[] account) + { + if (account.Length != 20) + throw new InvalidOperationException("The parameter account SHOULD be 20-byte addresses."); + StorageMap asset = Storage.CurrentContext.CreateMap(nameof(asset)); + return asset.Get(account).AsBigInteger(); //0.1 + } + [DisplayName("decimals")] + public static byte Decimals() => 8; + + [DisplayName("getRefundTarget")] + public static byte[] GetRefundTarget(byte[] txId) + { + if (txId.Length != 32) + throw new InvalidOperationException("The parameter txId SHOULD be 32-byte transaction hash."); + StorageMap refund = Storage.CurrentContext.CreateMap(nameof(refund)); + return refund.Get(txId); //0.1 + } + + [DisplayName("getTxInfo")] + public static TransferInfo GetTxInfo(byte[] txId) + { + if (txId.Length != 32) + throw new InvalidOperationException("The parameter txId SHOULD be 32-byte transaction hash."); + StorageMap txInfo = Storage.CurrentContext.CreateMap(nameof(txInfo)); + var result = txInfo.Get(txId); //0.1 + if (result.Length == 0) return null; + return Helper.Deserialize(result) as TransferInfo; + } + + private static bool IsPayable(byte[] to) + { + var c = Blockchain.GetContract(to); //0.1 + return c == null || c.IsPayable; + } + + /// + /// Global Asset -> NEP5 Asset + /// + [DisplayName("mintTokens")] + public static bool MintTokens() + { + var tx = ExecutionEngine.ScriptContainer as Transaction; + + //Person who sends a global asset, receives a NEP5 asset + byte[] sender = null; + var inputs = tx.GetReferences(); + foreach (var input in inputs) + { + if (input.AssetId.AsBigInteger() == AssetId.AsBigInteger()) + sender = sender ?? input.ScriptHash; + //SGAS address as inputs is not allowed + if (input.ScriptHash.AsBigInteger() == ExecutionEngine.ExecutingScriptHash.AsBigInteger()) + return false; + } + if (GetTxInfo(tx.Hash) != null) + return false; + + //Amount of exchange + var outputs = tx.GetOutputs(); + ulong value = 0; + foreach (var output in outputs) + { + if (output.ScriptHash == ExecutionEngine.ExecutingScriptHash && + output.AssetId.AsBigInteger() == AssetId.AsBigInteger()) + { + value += (ulong)output.Value; + } + } + + //Increase the total amount of contract assets + StorageMap contract = Storage.CurrentContext.CreateMap(nameof(contract)); + var totalSupply = contract.Get("totalSupply").AsBigInteger(); //0.1 + totalSupply += value; + contract.Put("totalSupply", totalSupply); //1 + + //Issue NEP-5 asset + StorageMap asset = Storage.CurrentContext.CreateMap(nameof(asset)); + var amount = asset.Get(sender).AsBigInteger(); //0.1 + asset.Put(sender, amount + value); //1 + + SetTxInfo(null, sender, value); + Transferred(null, sender, value); + return true; + } + + [DisplayName("name")] + public static string Name() => "NEP5 GAS"; + + /// + /// NEP5 Asset -> Global Asset + /// In the pre-refund phase you need to build a TX (SC -> SC) whose Input is a UTXO of the contract. + /// + [DisplayName("refund")] + public static bool Refund(byte[] from) + { + if (from.Length != 20) + throw new InvalidOperationException("The parameter from SHOULD be 20-byte addresses."); + var tx = ExecutionEngine.ScriptContainer as Transaction; + //output[0] Is the asset that the user want to refund + var preRefund = tx.GetOutputs()[0]; + //refund assets wrong, failed + if (preRefund.AssetId.AsBigInteger() != AssetId.AsBigInteger()) return false; + + //Not to itself, failed + if (preRefund.ScriptHash.AsBigInteger() != ExecutionEngine.ExecutingScriptHash.AsBigInteger()) return false; + + //double refund + StorageMap refund = Storage.CurrentContext.CreateMap(nameof(refund)); + if (refund.Get(tx.Hash).Length > 0) return false; //0.1 + + if (!Runtime.CheckWitness(from)) return false; //0.2 + + //Reduce the balance of the refund person + StorageMap asset = Storage.CurrentContext.CreateMap(nameof(asset)); + var fromAmount = asset.Get(from).AsBigInteger(); //0.1 + var preRefundValue = preRefund.Value; + if (fromAmount < preRefundValue) + return false; + else if (fromAmount == preRefundValue) + asset.Delete(from); //0.1 + else + asset.Put(from, fromAmount - preRefundValue); //1 + refund.Put(tx.Hash, from); //1 + + //Change the totalSupply + StorageMap contract = Storage.CurrentContext.CreateMap(nameof(contract)); + var totalSupply = contract.Get("totalSupply").AsBigInteger(); //0.1 + totalSupply -= preRefundValue; + contract.Put("totalSupply", totalSupply); //1 + + SetTxInfo(from, null, preRefundValue); + Transferred(from, null, preRefundValue); + Refunded(tx.Hash, from); + return true; + } + + private static void SetTxInfo(byte[] from, byte[] to, BigInteger value) + { + var txid = (ExecutionEngine.ScriptContainer as Transaction).Hash; + TransferInfo info = new TransferInfo + { + from = from, + to = to, + value = value + }; + StorageMap txInfo = Storage.CurrentContext.CreateMap(nameof(txInfo)); + txInfo.Put(txid, Helper.Serialize(info)); //1 + } + + [DisplayName("symbol")] + public static string Symbol() => "SGAS"; + + [DisplayName("supportedStandards")] + public static object SupportedStandards() => "{\"NEP-5\", \"NEP-7\", \"NEP-10\"}"; + + [DisplayName("totalSupply")] + public static BigInteger TotalSupply() + { + StorageMap contract = Storage.CurrentContext.CreateMap(nameof(contract)); + return contract.Get("totalSupply").AsBigInteger(); //0.1 + } +#if DEBUG + [DisplayName("transfer")] //Only for ABI file + public static bool Transfer(byte[] from, byte[] to, BigInteger amount) => true; +#endif + //Methods of actual execution + private static bool Transfer(byte[] from, byte[] to, BigInteger amount, byte[] callscript) + { + //Check parameters + if (from.Length != 20 || to.Length != 20) + throw new InvalidOperationException("The parameters from and to SHOULD be 20-byte addresses."); + if (amount <= 0) + throw new InvalidOperationException("The parameter amount MUST be greater than 0."); + if (ExecutionEngine.EntryScriptHash.AsBigInteger() != callscript.AsBigInteger()) + return false; + if (!IsPayable(to) || !Runtime.CheckWitness(from)/*0.2*/) + return false; + StorageMap asset = Storage.CurrentContext.CreateMap(nameof(asset)); + var fromAmount = asset.Get(from).AsBigInteger(); //0.1 + if (fromAmount < amount) + return false; + if (from == to) + return true; + + //Reduce payer balances + if (fromAmount == amount) + asset.Delete(from); //0.1 + else + asset.Put(from, fromAmount - amount); //1 + + //Increase the payee balance + var toAmount = asset.Get(to).AsBigInteger(); //0.1 + asset.Put(to, toAmount + amount); //1 + + SetTxInfo(from, to, amount); + Transferred(from, to, amount); + return true; + } +#if DEBUG + [DisplayName("transferAPP")] //Only for ABI file + public static bool TransferAPP(byte[] from, byte[] to, BigInteger amount) => true; +#endif + //Methods of actual execution + private static bool TransferAPP(byte[] from, byte[] to, BigInteger amount, byte[] callscript) + { + //Check parameters + if (from.Length != 20 || to.Length != 20) + throw new InvalidOperationException("The parameters from and to SHOULD be 20-byte addresses."); + if (amount <= 0) + throw new InvalidOperationException("The parameter amount MUST be greater than 0."); + if (!IsPayable(to) || from.AsBigInteger() != callscript.AsBigInteger()) + return false; + StorageMap asset = Storage.CurrentContext.CreateMap(nameof(asset)); + var fromAmount = asset.Get(from).AsBigInteger(); //0.1 + if (fromAmount < amount) + return false; + if (from == to) + return true; + + //Reduce payer balances + if (fromAmount == amount) + asset.Delete(from); //0.1 + else + asset.Put(from, fromAmount - amount); //1 + + //Increase the payee balance + var toAmount = asset.Get(to).AsBigInteger(); //0.1 + asset.Put(to, toAmount + amount); //1 + + SetTxInfo(from, to, amount); + Transferred(from, to, amount); + return true; + } + } +} \ No newline at end of file diff --git a/NeoContract/SGAS.csproj b/NeoContract/SGAS.csproj new file mode 100644 index 0000000..afce986 --- /dev/null +++ b/NeoContract/SGAS.csproj @@ -0,0 +1,67 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {15DFB6B6-A57D-4A26-A5B7-EA1B2D102E20} + Library + Properties + SGAS + SGAS + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + none + true + bin\Release\ + + + prompt + 4 + + + + False + .\Neo.SmartContract.Framework.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NeoContract/TransferInfo.cs b/NeoContract/TransferInfo.cs new file mode 100644 index 0000000..81764ee --- /dev/null +++ b/NeoContract/TransferInfo.cs @@ -0,0 +1,11 @@ +using System.Numerics; + +namespace SGAS +{ + public class TransferInfo + { + public byte[] from; + public byte[] to; + public BigInteger value; + } +} diff --git a/NeoContract/build.tasks b/NeoContract/build.tasks new file mode 100644 index 0000000..87cd344 --- /dev/null +++ b/NeoContract/build.tasks @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/SGAS.UnitTests/App.config b/SGAS.UnitTests/App.config new file mode 100644 index 0000000..8362bcf --- /dev/null +++ b/SGAS.UnitTests/App.config @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SGAS.UnitTests/Program.cs b/SGAS.UnitTests/Program.cs new file mode 100644 index 0000000..c1f0881 --- /dev/null +++ b/SGAS.UnitTests/Program.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Numerics; +using Neo; +using Neo.Core; +using Neo.Implementations.Blockchains.LevelDB; +using Neo.IO; +using Neo.SmartContract; +using Neo.VM; +using Neo.Wallets; +using VMArray = Neo.VM.Types.Array; + +namespace NeoContract.UnitTests +{ + class Program + { + static void Main(string[] args) + { + //Need libleveldb.dll, and requires a platform(x86 or x64) that is consistent with the program. + //Path of blockchain folder + Blockchain.RegisterBlockchain(new LevelDBBlockchain("C:\\Users\\chenz\\Desktop\\PrivateNet\\neo-gui 2.7.6\\Chain_0001142D")); + + SGASTest.MintTokens(); + //SGASTest.Refund(); + //SGASTest.Verify(); + + Console.ReadLine(); + } + } +} diff --git a/SGAS.UnitTests/Properties/AssemblyInfo.cs b/SGAS.UnitTests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..1372e16 --- /dev/null +++ b/SGAS.UnitTests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("ConsoleApp2")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ConsoleApp2")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("5c287cb0-fc56-482a-8c91-db83b60c9b70")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 +// 方法是按如下所示使用“*”: : +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SGAS.UnitTests/SGAS.UnitTests.csproj b/SGAS.UnitTests/SGAS.UnitTests.csproj new file mode 100644 index 0000000..a382cbd --- /dev/null +++ b/SGAS.UnitTests/SGAS.UnitTests.csproj @@ -0,0 +1,243 @@ + + + + + Debug + AnyCPU + {5C287CB0-FC56-482A-8C91-DB83B60C9B70} + Exe + SGAS.UnitTests + SGAS.UnitTests + v4.7.1 + 512 + true + + + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Microsoft.AspNetCore.Hosting.2.0.3\lib\netstandard2.0\Microsoft.AspNetCore.Hosting.dll + + + ..\packages\Microsoft.AspNetCore.Hosting.Abstractions.2.0.3\lib\netstandard2.0\Microsoft.AspNetCore.Hosting.Abstractions.dll + + + ..\packages\Microsoft.AspNetCore.Hosting.Server.Abstractions.2.0.3\lib\netstandard2.0\Microsoft.AspNetCore.Hosting.Server.Abstractions.dll + + + ..\packages\Microsoft.AspNetCore.Http.2.0.3\lib\netstandard2.0\Microsoft.AspNetCore.Http.dll + + + ..\packages\Microsoft.AspNetCore.Http.Abstractions.2.0.3\lib\netstandard2.0\Microsoft.AspNetCore.Http.Abstractions.dll + + + ..\packages\Microsoft.AspNetCore.Http.Extensions.2.0.3\lib\netstandard2.0\Microsoft.AspNetCore.Http.Extensions.dll + + + ..\packages\Microsoft.AspNetCore.Http.Features.2.0.3\lib\netstandard2.0\Microsoft.AspNetCore.Http.Features.dll + + + ..\packages\Microsoft.AspNetCore.ResponseCompression.2.0.3\lib\net461\Microsoft.AspNetCore.ResponseCompression.dll + + + ..\packages\Microsoft.AspNetCore.Server.Kestrel.2.0.3\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.dll + + + ..\packages\Microsoft.AspNetCore.Server.Kestrel.Core.2.0.3\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Core.dll + + + ..\packages\Microsoft.AspNetCore.Server.Kestrel.Https.2.0.3\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Https.dll + + + ..\packages\Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.2.0.3\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.dll + + + ..\packages\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.2.0.3\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.dll + + + ..\packages\Microsoft.AspNetCore.WebSockets.2.0.3\lib\netstandard2.0\Microsoft.AspNetCore.WebSockets.dll + + + ..\packages\Microsoft.AspNetCore.WebUtilities.2.0.3\lib\netstandard2.0\Microsoft.AspNetCore.WebUtilities.dll + + + ..\packages\Microsoft.Data.Sqlite.Core.2.0.1\lib\netstandard2.0\Microsoft.Data.Sqlite.dll + + + ..\packages\Microsoft.EntityFrameworkCore.2.0.3\lib\netstandard2.0\Microsoft.EntityFrameworkCore.dll + + + ..\packages\Microsoft.EntityFrameworkCore.Relational.2.0.3\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Relational.dll + + + ..\packages\Microsoft.EntityFrameworkCore.Sqlite.Core.2.0.3\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Sqlite.dll + + + ..\packages\Microsoft.Extensions.Caching.Abstractions.2.0.2\lib\netstandard2.0\Microsoft.Extensions.Caching.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Caching.Memory.2.0.2\lib\netstandard2.0\Microsoft.Extensions.Caching.Memory.dll + + + ..\packages\Microsoft.Extensions.Configuration.2.0.2\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll + + + ..\packages\Microsoft.Extensions.Configuration.Abstractions.2.0.2\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Configuration.EnvironmentVariables.2.0.2\lib\netstandard2.0\Microsoft.Extensions.Configuration.EnvironmentVariables.dll + + + ..\packages\Microsoft.Extensions.Configuration.FileExtensions.2.0.2\lib\netstandard2.0\Microsoft.Extensions.Configuration.FileExtensions.dll + + + ..\packages\Microsoft.Extensions.Configuration.Json.2.0.2\lib\netstandard2.0\Microsoft.Extensions.Configuration.Json.dll + + + ..\packages\Microsoft.Extensions.DependencyInjection.2.0.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.dll + + + ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.0.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + + ..\packages\Microsoft.Extensions.FileProviders.Abstractions.2.0.1\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Abstractions.dll + + + ..\packages\Microsoft.Extensions.FileProviders.Physical.2.0.1\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Physical.dll + + + ..\packages\Microsoft.Extensions.FileSystemGlobbing.2.0.1\lib\netstandard2.0\Microsoft.Extensions.FileSystemGlobbing.dll + + + ..\packages\Microsoft.Extensions.Hosting.Abstractions.2.0.3\lib\netstandard2.0\Microsoft.Extensions.Hosting.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Logging.2.0.2\lib\netstandard2.0\Microsoft.Extensions.Logging.dll + + + ..\packages\Microsoft.Extensions.Logging.Abstractions.2.0.2\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll + + + ..\packages\Microsoft.Extensions.ObjectPool.2.0.0\lib\netstandard2.0\Microsoft.Extensions.ObjectPool.dll + + + ..\packages\Microsoft.Extensions.Options.2.0.2\lib\netstandard2.0\Microsoft.Extensions.Options.dll + + + ..\packages\Microsoft.Extensions.Primitives.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll + + + ..\packages\Microsoft.Net.Http.Headers.2.0.3\lib\netstandard2.0\Microsoft.Net.Http.Headers.dll + + + ..\packages\Neo.2.8.0\lib\net47\Neo.dll + + + ..\packages\Neo.VM.2.3.1\lib\net461\Neo.VM.dll + + + ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll + + + ..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll + + + ..\packages\Replicon.Cryptography.SCrypt.1.1.6.13\lib\net40\Replicon.Cryptography.SCrypt.dll + + + ..\packages\SQLitePCLRaw.bundle_green.1.1.11\lib\net45\SQLitePCLRaw.batteries_green.dll + + + ..\packages\SQLitePCLRaw.bundle_green.1.1.11\lib\net45\SQLitePCLRaw.batteries_v2.dll + + + ..\packages\SQLitePCLRaw.core.1.1.11\lib\net45\SQLitePCLRaw.core.dll + + + ..\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.11\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll + + + + ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll + + + ..\packages\System.Collections.Immutable.1.4.0\lib\netstandard2.0\System.Collections.Immutable.dll + + + ..\packages\System.ComponentModel.Annotations.4.4.1\lib\net461\System.ComponentModel.Annotations.dll + + + + + + ..\packages\System.Diagnostics.DiagnosticSource.4.4.1\lib\net46\System.Diagnostics.DiagnosticSource.dll + + + ..\packages\System.Interactive.Async.3.1.1\lib\net46\System.Interactive.Async.dll + + + + ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Reflection.Metadata.1.5.0\lib\netstandard2.0\System.Reflection.Metadata.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.4.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + + + ..\packages\System.Text.Encodings.Web.4.4.0\lib\netstandard2.0\System.Text.Encodings.Web.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.4.0\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll + + + + + + + + + + + + + + + + + + + + + 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 + + + + + + + + \ No newline at end of file diff --git a/SGAS.UnitTests/SGASTest.cs b/SGAS.UnitTests/SGASTest.cs new file mode 100644 index 0000000..d0a05d8 --- /dev/null +++ b/SGAS.UnitTests/SGASTest.cs @@ -0,0 +1,312 @@ +using Neo; +using Neo.Core; +using Neo.IO; +using Neo.SmartContract; +using Neo.VM; +using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NeoContract.UnitTests +{ + public static class SGASTest + { + static readonly UInt160 SgasAddress = Wallet.ToScriptHash("AJk6Ugmz2bJGhoye9EAnssvvLghf6YmptA"); + static readonly UInt160 ScriptHash = new UInt160("0x3cfb49c6eb5360440bdd226528ada99e8d419220".Remove(0, 2).HexToBytes().Reverse().ToArray()); + static readonly UInt160 User = Wallet.ToScriptHash("AJd31a8rYPEBkY1QSxpsGy8mdU4vTYTD4U"); + static readonly byte[] UserScript = "2103ad1d70f140d84a90ad4491cdf175fa64bfa9287a006e8cbd8f8db8500b5205baac".HexToBytes(); + + //SGAS MintTokens + public static void MintTokens() + { + var inputs = new List { + //coin reference A + new CoinReference(){ + PrevHash = new UInt256("0xf5088ce508d86197c991ff0ef7651ddf01f3e555f257039c972082250e899210".Remove(0, 2).HexToBytes().Reverse().ToArray()), + PrevIndex = 0 //16639 GAS + } + }.ToArray(); + + var outputs = new List{ new TransactionOutput() + { + AssetId = Blockchain.UtilityToken.Hash, //Asset Id, this is GAS + ScriptHash = SgasAddress, //SGAS 地址 + Value = new Fixed8((long)(1 * (long)Math.Pow(10, 8))) //Value + }}.ToArray(); + + Transaction tx = null; + + using (ScriptBuilder sb = new ScriptBuilder()) + { + sb.EmitAppCall(ScriptHash, "mintTokens"); + sb.Emit(OpCode.THROWIFNOT); + + byte[] nonce = new byte[8]; + Random rand = new Random(); + rand.NextBytes(nonce); + sb.Emit(OpCode.RET, nonce); + tx = new InvocationTransaction + { + Version = 1, + Script = sb.ToArray(), + Outputs = outputs, + Inputs = inputs, + Attributes = new TransactionAttribute[0], + Scripts = new Witness[0] + }; + } + + if (tx == null) + { + Console.WriteLine("Create Transaction Failed"); + Console.ReadLine(); + return; + } + + //Open wallet + var wallet = new Neo.Implementations.Wallets.NEP6.NEP6Wallet("0.json"); + try + { + wallet.Unlock("1"); + } + catch (Exception) + { + Console.WriteLine("password error"); + } + + //Sign in wallet + var context = new ContractParametersContext(tx); + wallet.Sign(context); + if (context.Completed) + { + Console.WriteLine("Sign Successful"); + tx.Scripts = context.GetScripts(); + } + else + { + Console.WriteLine("Sign Faild"); + } + + try + { + tx = Transaction.DeserializeFrom(tx.ToArray()); + } + catch (Exception) + { + Console.WriteLine("Invalid Transaction Format"); + } + + Console.WriteLine("Verify Transaction:" + tx.Verify(new List { tx })); + + Console.WriteLine("Raw Transaction:"); + Console.WriteLine(tx.ToArray().ToHexString()); + + //Then Call neo-cli API:sendrawtransaction in postman. + } + + public static void Refund() + { + var inputs = new List { + new CoinReference(){ + PrevHash = new UInt256("0xdb4c4f1a17b365a68497ef0e118db89b827db24f67ee71d317d38c68c84424ef".Remove(0, 2).HexToBytes().Reverse().ToArray()), + PrevIndex = 0 //1 + } + }.ToArray(); + + var outputs = new List{ new TransactionOutput() + { + AssetId = Blockchain.UtilityToken.Hash, //Asset Id, this is GAS + ScriptHash = SgasAddress, //SGAS 地址 + Value = new Fixed8((long)(1 * (long)Math.Pow(10, 8))) //Value + }}.ToArray(); + + Transaction tx = null; + + var applicationScript = new byte[0]; + + using (ScriptBuilder sb = new ScriptBuilder()) + { + sb.EmitAppCall(ScriptHash, "refund", User); + sb.Emit(OpCode.THROWIFNOT); + applicationScript = sb.ToArray(); + } + + tx = new InvocationTransaction + { + Version = 0, + Script = applicationScript, + Outputs = outputs, + Inputs = inputs, + Attributes = new TransactionAttribute[] + { + new TransactionAttribute + { + Usage = TransactionAttributeUsage.Script, + Data = User.ToArray()//附加人的 Script Hash + } + } + }; + + + if (tx == null) + { + Console.WriteLine("Create Transaction Failed"); + Console.ReadLine(); + return; + } + + //Open wallet + var wallet = new Neo.Implementations.Wallets.NEP6.NEP6Wallet("0.json"); + try + { + wallet.Unlock("1"); + } + catch (Exception) + { + Console.WriteLine("password error"); + } + + //Sign in wallet 生成附加人的签名 + var context = new ContractParametersContext(tx); + var additionalSignature = new byte[0]; + foreach (UInt160 hash in context.ScriptHashes) + { + if (hash == User) + { + WalletAccount account = wallet.GetAccount(hash); + if (account?.HasKey != true) continue; + KeyPair key = account.GetKey(); + additionalSignature = context.Verifiable.Sign(key); + } + } + var additionalVerificationScript = new byte[0]; + using (ScriptBuilder sb = new ScriptBuilder()) + { + sb.EmitPush(additionalSignature); + additionalVerificationScript = sb.ToArray(); + } + var verificationScript = new byte[0]; + using (ScriptBuilder sb = new ScriptBuilder()) + { + sb.EmitPush(2); + sb.EmitPush("1"); + verificationScript = sb.ToArray(); + } + var witness = new Witness + { + InvocationScript = verificationScript, + VerificationScript = Blockchain.Default.GetContract(ScriptHash).Script + }; + var additionalWitness = new Witness + { + InvocationScript = additionalVerificationScript, + VerificationScript = UserScript + }; + var witnesses = new Witness[2] { witness, additionalWitness }; + tx.Scripts = witnesses.ToList().OrderBy(p => p.ScriptHash).ToArray(); + + try + { + tx = Transaction.DeserializeFrom(tx.ToArray()); + } + catch (Exception) + { + Console.WriteLine("Invalid Transaction Format"); + } + + if (tx.Verify(new List { tx })) + { + Console.WriteLine("Verify Transaction: True"); + Console.WriteLine("Raw Transaction:"); + Console.WriteLine(tx.ToArray().ToHexString()); + //Console.WriteLine(tx.ToJson()); + + + //Then Call neo-cli API:sendrawtransaction in postman. + } + else + { + Console.WriteLine("Verify Transaction: False"); + } + } + + public static void Verify() + { + var inputs = new List { + new CoinReference(){ + PrevHash = new UInt256("0xdb4c4f1a17b365a68497ef0e118db89b827db24f67ee71d317d38c68c84424ef".Remove(0, 2).HexToBytes().Reverse().ToArray()), + PrevIndex = 0 //1 + } + }.ToArray(); + + var outputs = new List{ new TransactionOutput() + { + AssetId = Blockchain.UtilityToken.Hash, //Asset Id, this is GAS + ScriptHash = SgasAddress,//SGAS 地址 + Value = new Fixed8((long)(1 * (long)Math.Pow(10, 8))) //Value + }}.ToArray(); + + Transaction tx = null; + + var verificationScript = new byte[0]; + using (ScriptBuilder sb = new ScriptBuilder()) + { + sb.EmitPush(2); + sb.EmitPush("1"); + verificationScript = sb.ToArray(); + } + + var witness = new Witness + { + InvocationScript = verificationScript, + //未部署的合约不能执行 Storage.Get() 方法,所以要将合约部署,而不是调用本地的 AVM 文件 + //VerificationScript = File.ReadAllBytes("C:\\Users\\chenz\\Documents\\1Code\\chenzhitong\\NeoContract5\\NeoContract\\bin\\Debug\\SGAS.avm") + VerificationScript = Blockchain.Default.GetContract(ScriptHash).Script + }; + tx = new InvocationTransaction + { + Version = 0, + Script = new byte[0], + Outputs = outputs, + Inputs = inputs, + Attributes = new TransactionAttribute[0], + Scripts = new Witness[] { witness } + }; + + + if (tx == null) + { + Console.WriteLine("Create Transaction Failed"); + Console.ReadLine(); + return; + } + + try + { + tx = Transaction.DeserializeFrom(tx.ToArray()); + } + catch (Exception) + { + Console.WriteLine("Invalid Transaction Format"); + } + if (tx.Verify(new List { tx })) + { + Console.WriteLine("Verify Transaction: True"); + Console.WriteLine("Raw Transaction:"); + Console.WriteLine(tx.ToArray().ToHexString()); + //Console.WriteLine(tx.ToJson()); + + + //Then Call neo-cli API:sendrawtransaction in postman. + } + else + { + Console.WriteLine("Verify Transaction: False"); + } + } + } +} diff --git a/SGAS.UnitTests/packages.config b/SGAS.UnitTests/packages.config new file mode 100644 index 0000000..233e880 --- /dev/null +++ b/SGAS.UnitTests/packages.config @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tools/App.config b/Tools/App.config new file mode 100644 index 0000000..731f6de --- /dev/null +++ b/Tools/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Tools/Program.cs b/Tools/Program.cs new file mode 100644 index 0000000..d3b144b --- /dev/null +++ b/Tools/Program.cs @@ -0,0 +1,65 @@ +using Neo; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace ConsoleApp1 +{ + static class Program + { + static void Main(string[] args) + { + //address 2 script hash + Console.WriteLine(Neo.Wallets.Wallet.ToScriptHash("AJd31a8rYPEBkY1QSxpsGy8mdU4vTYTD4U")); + //script hash 2 address + Console.WriteLine(Neo.Wallets.Wallet.ToAddress(new UInt160("0xeee76c45175b5af08630b2278a24803368284a1e".Remove(0, 2).HexToBytes().Reverse().ToArray()))); + + //hex string 2 string + Console.WriteLine("7472616e73666572".HexToString()); + //string 2 hex string + Console.WriteLine("transfer".ToHexString()); + + //big-endian 2 little-endian + Console.WriteLine("0x4701ee0b674ff2d8893effc2607be85327733c1f".Remove(0, 2).HexToBytes().Reverse().ToHexString()); + //little-endian 2 big-endian + Console.WriteLine("0x" + "b1ad4a4093e7b918d19b013b7347cf0a67bed8ac6ca393ea9a473841b6ef3523".HexToBytes().Reverse().ToHexString()); + + //hex string 2 biginteger + Console.WriteLine(new BigInteger("00e1f505".HexToBytes())); + //biginteger 2 hex string + Console.WriteLine(new BigInteger(100000000).ToByteArray().ToHexString()); + + Console.ReadLine(); + } + + static string HexToString(this string hex) + { + if (hex.Length % 2 != 0) + { + throw new ArgumentException(); + } + var output = ""; + for (int i = 0; i <= hex.Length - 2; i+=2) + { + try + { + var result = Convert.ToByte(new string(hex.Skip(i).Take(2).ToArray()), 16); + output += (Convert.ToChar(result)); + } + catch (Exception) + { + throw; + } + } + return output; + } + static string ToHexString(this string str) + { + byte[] byteArray = Encoding.Default.GetBytes(str.ToCharArray()); + return byteArray.ToHexString(); + } + } +} diff --git a/Tools/Properties/AssemblyInfo.cs b/Tools/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..298da42 --- /dev/null +++ b/Tools/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("ConsoleApp1")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ConsoleApp1")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("a4f2d281-a2e9-4950-aa18-098bf614fd6c")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 +// 方法是按如下所示使用“*”: : +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Tools/Tools.csproj b/Tools/Tools.csproj new file mode 100644 index 0000000..49b56a0 --- /dev/null +++ b/Tools/Tools.csproj @@ -0,0 +1,237 @@ + + + + + Debug + AnyCPU + {A4F2D281-A2E9-4950-AA18-098BF614FD6C} + Exe + ConsoleApp1 + ConsoleApp1 + v4.6.1 + 512 + true + + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\Microsoft.AspNetCore.Hosting.2.0.2\lib\netstandard2.0\Microsoft.AspNetCore.Hosting.dll + + + ..\packages\Microsoft.AspNetCore.Hosting.Abstractions.2.0.2\lib\netstandard2.0\Microsoft.AspNetCore.Hosting.Abstractions.dll + + + ..\packages\Microsoft.AspNetCore.Hosting.Server.Abstractions.2.0.2\lib\netstandard2.0\Microsoft.AspNetCore.Hosting.Server.Abstractions.dll + + + ..\packages\Microsoft.AspNetCore.Http.2.0.2\lib\netstandard2.0\Microsoft.AspNetCore.Http.dll + + + ..\packages\Microsoft.AspNetCore.Http.Abstractions.2.0.2\lib\netstandard2.0\Microsoft.AspNetCore.Http.Abstractions.dll + + + ..\packages\Microsoft.AspNetCore.Http.Extensions.2.0.2\lib\netstandard2.0\Microsoft.AspNetCore.Http.Extensions.dll + + + ..\packages\Microsoft.AspNetCore.Http.Features.2.0.2\lib\netstandard2.0\Microsoft.AspNetCore.Http.Features.dll + + + ..\packages\Microsoft.AspNetCore.ResponseCompression.2.0.2\lib\net461\Microsoft.AspNetCore.ResponseCompression.dll + + + ..\packages\Microsoft.AspNetCore.Server.Kestrel.2.0.2\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.dll + + + ..\packages\Microsoft.AspNetCore.Server.Kestrel.Core.2.0.2\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Core.dll + + + ..\packages\Microsoft.AspNetCore.Server.Kestrel.Https.2.0.2\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Https.dll + + + ..\packages\Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.2.0.2\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.dll + + + ..\packages\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.2.0.2\lib\netstandard2.0\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.dll + + + ..\packages\Microsoft.AspNetCore.WebSockets.2.0.2\lib\netstandard2.0\Microsoft.AspNetCore.WebSockets.dll + + + ..\packages\Microsoft.AspNetCore.WebUtilities.2.0.2\lib\netstandard2.0\Microsoft.AspNetCore.WebUtilities.dll + + + ..\packages\Microsoft.Data.Sqlite.Core.2.0.1\lib\netstandard2.0\Microsoft.Data.Sqlite.dll + + + ..\packages\Microsoft.EntityFrameworkCore.2.0.2\lib\netstandard2.0\Microsoft.EntityFrameworkCore.dll + + + ..\packages\Microsoft.EntityFrameworkCore.Relational.2.0.2\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Relational.dll + + + ..\packages\Microsoft.EntityFrameworkCore.Sqlite.Core.2.0.2\lib\netstandard2.0\Microsoft.EntityFrameworkCore.Sqlite.dll + + + ..\packages\Microsoft.Extensions.Caching.Abstractions.2.0.1\lib\netstandard2.0\Microsoft.Extensions.Caching.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Caching.Memory.2.0.1\lib\netstandard2.0\Microsoft.Extensions.Caching.Memory.dll + + + ..\packages\Microsoft.Extensions.Configuration.2.0.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll + + + ..\packages\Microsoft.Extensions.Configuration.Abstractions.2.0.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Configuration.EnvironmentVariables.2.0.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.EnvironmentVariables.dll + + + ..\packages\Microsoft.Extensions.Configuration.FileExtensions.2.0.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.FileExtensions.dll + + + ..\packages\Microsoft.Extensions.Configuration.Json.2.0.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.Json.dll + + + ..\packages\Microsoft.Extensions.DependencyInjection.2.0.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.dll + + + ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.0.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + + ..\packages\Microsoft.Extensions.FileProviders.Abstractions.2.0.1\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Abstractions.dll + + + ..\packages\Microsoft.Extensions.FileProviders.Physical.2.0.1\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Physical.dll + + + ..\packages\Microsoft.Extensions.FileSystemGlobbing.2.0.1\lib\netstandard2.0\Microsoft.Extensions.FileSystemGlobbing.dll + + + ..\packages\Microsoft.Extensions.Hosting.Abstractions.2.0.2\lib\netstandard2.0\Microsoft.Extensions.Hosting.Abstractions.dll + + + ..\packages\Microsoft.Extensions.Logging.2.0.1\lib\netstandard2.0\Microsoft.Extensions.Logging.dll + + + ..\packages\Microsoft.Extensions.Logging.Abstractions.2.0.1\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll + + + ..\packages\Microsoft.Extensions.ObjectPool.2.0.0\lib\netstandard2.0\Microsoft.Extensions.ObjectPool.dll + + + ..\packages\Microsoft.Extensions.Options.2.0.1\lib\netstandard2.0\Microsoft.Extensions.Options.dll + + + ..\packages\Microsoft.Extensions.Primitives.2.0.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll + + + ..\packages\Microsoft.Net.Http.Headers.2.0.2\lib\netstandard2.0\Microsoft.Net.Http.Headers.dll + + + ..\packages\Neo.2.7.6.1\lib\netstandard2.0\Neo.dll + + + ..\packages\Neo.VM.2.2.0\lib\net461\Neo.VM.dll + + + ..\packages\Newtonsoft.Json.10.0.1\lib\net45\Newtonsoft.Json.dll + + + ..\packages\Remotion.Linq.2.1.1\lib\net45\Remotion.Linq.dll + + + ..\packages\SQLitePCLRaw.bundle_green.1.1.7\lib\net45\SQLitePCLRaw.batteries_green.dll + + + ..\packages\SQLitePCLRaw.bundle_green.1.1.7\lib\net45\SQLitePCLRaw.batteries_v2.dll + + + ..\packages\SQLitePCLRaw.core.1.1.7\lib\net45\SQLitePCLRaw.core.dll + + + ..\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.7\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll + + + + ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll + + + ..\packages\System.Collections.Immutable.1.4.0\lib\netstandard2.0\System.Collections.Immutable.dll + + + ..\packages\System.ComponentModel.Annotations.4.4.0\lib\net461\System.ComponentModel.Annotations.dll + + + + + + ..\packages\System.Diagnostics.DiagnosticSource.4.4.1\lib\net46\System.Diagnostics.DiagnosticSource.dll + + + ..\packages\System.Interactive.Async.3.1.1\lib\net46\System.Interactive.Async.dll + + + + ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll + + + ..\packages\System.Reflection.Metadata.1.5.0\lib\netstandard2.0\System.Reflection.Metadata.dll + + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.4.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Text.Encodings.Web.4.4.0\lib\netstandard2.0\System.Text.Encodings.Web.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.4.0\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll + + + + + + + + + + + + + + + + + + + + + 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 + + + + + + + + \ No newline at end of file diff --git a/Tools/packages.config b/Tools/packages.config new file mode 100644 index 0000000..4ebf2fb --- /dev/null +++ b/Tools/packages.config @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..f974a7c --- /dev/null +++ b/readme.md @@ -0,0 +1,45 @@ +## Unit test result + +Test environment: + +private net + +neo-cli 2.7.6 (must > 2.7.5) + +neo-gui 2.7.6 + +| Method | Description | How to test | Test Result | +| ------------------------ | ---------------------------------- | ------------------------------ | ----------- | +| balanceOf | see nep-5 | neo-gui | ✅ | +| decimals | see nep-5 | neo-gui | ✅ | +| getRefundTarget | get who want to refund this UTXO | neo-gui | ✅ | +| getTxInfo | get tx info | neo-gui | ✅ | +| mintTokens | GAS → SGAS | c# code + neo-cli | ✅ | +| name | see nep-5 | neo-gui | ✅ | +| refund | SGAS → GAS 1/2 step | c# code + neo-cli | ✅ | +| symbol | see nep-5 | neo-gui | ✅ | +| totalSupply | see nep-5 | neo-gui | ✅ | +| transfer | see nep-5 | neo-gui or neo-cli | ✅ | +| transferAPP | transfer from other smart contract | neo-gui + other smart contract | ✅ | +| TriggerType.Verification | | c# code + neo-cli | ✅ | + +Useful Test Tools: [https://github.com/chenzhitong/ApplicationLogsTools](https://github.com/chenzhitong/ApplicationLogsTools) + +备注: + +Verification 触发器执行时如果有参数需要传参,否则会因为栈不平而失败 + +Verification 触发器的参数要放在交易的 Witness 的 InvocationScript 字段中,可以用 ScriptBuilder 来构造 + +Verification 触发器中不能执行下面的代码 +var callscript = ExecutionEngine.CallingScriptHash; + +未部署的合约不能执行 Storage.Get() 方法 + +Storage.Get() 如果查询不到的话,返回 byte[0] 而不是 null + +Application 触发器中如果调用 CheckWitness() 的话,需要在 TransactionAttribute 中传附加人的签名 Usage = TransactionAttributeUsage.Script Data = ScriptHash,并且在 Scripts 中添加一个新的 Witness + +推荐使用 StorageMap 来读写存储区,而不是直接用 Storage.Get 或 Storage.Put + +NEP-5 中,参数错误应该抛出异常,而不是返回 false