├── .gitattributes ├── .gitignore ├── BitcoinTransactionTool.sln ├── BitcoinTransactionTool ├── App.config ├── App.xaml ├── App.xaml.cs ├── Backend │ ├── Address.cs │ ├── Blockchain │ │ ├── ITransaction.cs │ │ ├── Outpoint.cs │ │ ├── Scripts │ │ │ ├── IPubkeyScript.cs │ │ │ ├── IRedeemScript.cs │ │ │ ├── IScript.cs │ │ │ ├── ISignatureScript.cs │ │ │ ├── IWitnessScript.cs │ │ │ ├── OP.cs │ │ │ ├── Operations │ │ │ │ ├── ArithmeticOps.cs │ │ │ │ ├── BaseOperation.cs │ │ │ │ ├── CheckSigOps.cs │ │ │ │ ├── CryptoOps.cs │ │ │ │ ├── EqualityOps.cs │ │ │ │ ├── FlowControlOps.cs │ │ │ │ ├── IOpData.cs │ │ │ │ ├── IOperation.cs │ │ │ │ ├── LockTimeOps.cs │ │ │ │ ├── NotRunableOps.cs │ │ │ │ ├── OpData.cs │ │ │ │ ├── OpHelper.cs │ │ │ │ ├── PushDataOp.cs │ │ │ │ ├── ReturnOp.cs │ │ │ │ ├── SimpleRunableOps.cs │ │ │ │ ├── SizeOp.cs │ │ │ │ ├── StackOps.cs │ │ │ │ └── VerifyOp.cs │ │ │ ├── PubkeyScript.cs │ │ │ ├── RedeemScript.cs │ │ │ ├── Script.cs │ │ │ ├── ScriptTypeEnums.cs │ │ │ ├── SignatureScript.cs │ │ │ └── WitnessScript.cs │ │ ├── Transaction.cs │ │ ├── TxIn.cs │ │ └── TxOut.cs │ ├── CompactInt.cs │ ├── Constants.cs │ ├── Cryptography │ │ └── Hashing │ │ │ ├── IHashFunction.cs │ │ │ ├── Ripemd160.cs │ │ │ ├── Ripemd160Sha256.cs │ │ │ ├── Sha1.cs │ │ │ └── Sha256.cs │ ├── Encoders │ │ ├── Base16.cs │ │ ├── Base43.cs │ │ ├── Base58.cs │ │ └── Bech32.cs │ ├── ExtentionsAndHelpers.cs │ ├── IDeserializable.cs │ ├── JsonConverterHelper.cs │ ├── LockTime.cs │ ├── MVVM │ │ ├── BindableCommand.cs │ │ ├── DependsOnPropertyAttribute.cs │ │ ├── InpcBase.cs │ │ ├── ValidatableBase.cs │ │ └── ViewModelBase.cs │ └── StackInt.cs ├── Bitcoin Icon.png.ico ├── BitcoinTransactionTool.csproj ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── Models │ ├── BitcoinAddress.cs │ ├── ButtonModel.cs │ ├── PublicKeyModel.cs │ └── UTXO.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── Services │ ├── Api.cs │ ├── ErrorCollection.cs │ ├── OperationConverter.cs │ ├── PushServices.cs │ ├── Response.cs │ ├── ScriptReader.cs │ ├── ScriptToStringConverter.cs │ ├── TransactionServices │ │ ├── BlockCypher.cs │ │ └── BlockchainInfo.cs │ ├── TxBuilder.cs │ └── WindowManager.cs ├── ViewModels │ ├── MainWindowViewModel.cs │ ├── QrViewModel.cs │ ├── ScrAddressViewModel.cs │ ├── ScrArbitraryDataViewModel.cs │ ├── ScrHashCollisionViewModel.cs │ ├── ScrMultiSigViewModel.cs │ ├── ScriptVMBase.cs │ ├── ScriptViewModel.cs │ ├── TransactionEditViewModel.cs │ └── TxJsonViewModel.cs ├── Views │ ├── QrView.xaml │ ├── QrView.xaml.cs │ ├── ScrAddressView.xaml │ ├── ScrAddressView.xaml.cs │ ├── ScrArbitraryDataView.xaml │ ├── ScrArbitraryDataView.xaml.cs │ ├── ScrHashCollisionView.xaml │ ├── ScrHashCollisionView.xaml.cs │ ├── ScrMultiSigView.xaml │ ├── ScrMultiSigView.xaml.cs │ ├── ScriptView.xaml │ ├── ScriptView.xaml.cs │ ├── TransactionEditView.xaml │ ├── TransactionEditView.xaml.cs │ ├── TxJsonView.xaml │ └── TxJsonView.xaml.cs └── packages.config ├── CommonLibrary ├── AsyncCommand.cs ├── AsyncCommandBase.cs ├── BitcoinConversions.cs ├── CommonLibrary.csproj ├── NotifyTaskCompletion.cs └── Properties │ └── AssemblyInfo.cs ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # Roslyn cache directories 20 | *.ide/ 21 | 22 | # MSTest test Results 23 | [Tt]est[Rr]esult*/ 24 | [Bb]uild[Ll]og.* 25 | 26 | #NUNIT 27 | *.VisualState.xml 28 | TestResult.xml 29 | 30 | # Build Results of an ATL Project 31 | [Dd]ebugPS/ 32 | [Rr]eleasePS/ 33 | dlldata.c 34 | 35 | *_i.c 36 | *_p.c 37 | *_i.h 38 | *.ilk 39 | *.meta 40 | *.obj 41 | *.pch 42 | *.pdb 43 | *.pgc 44 | *.pgd 45 | *.rsp 46 | *.sbr 47 | *.tlb 48 | *.tli 49 | *.tlh 50 | *.tmp 51 | *.tmp_proj 52 | *.log 53 | *.vspscc 54 | *.vssscc 55 | .builds 56 | *.pidb 57 | *.svclog 58 | *.scc 59 | 60 | # Chutzpah Test files 61 | _Chutzpah* 62 | 63 | # Visual C++ cache files 64 | ipch/ 65 | *.aps 66 | *.ncb 67 | *.opensdf 68 | *.sdf 69 | *.cachefile 70 | 71 | # Visual Studio profiler 72 | *.psess 73 | *.vsp 74 | *.vspx 75 | 76 | # TFS 2012 Local Workspace 77 | $tf/ 78 | 79 | # Guidance Automation Toolkit 80 | *.gpState 81 | 82 | # ReSharper is a .NET coding add-in 83 | _ReSharper*/ 84 | *.[Rr]e[Ss]harper 85 | *.DotSettings.user 86 | 87 | # JustCode is a .NET coding addin-in 88 | .JustCode 89 | 90 | # TeamCity is a build add-in 91 | _TeamCity* 92 | 93 | # DotCover is a Code Coverage Tool 94 | *.dotCover 95 | 96 | # NCrunch 97 | _NCrunch_* 98 | .*crunch*.local.xml 99 | 100 | # MightyMoose 101 | *.mm.* 102 | AutoTest.Net/ 103 | 104 | # Web workbench (sass) 105 | .sass-cache/ 106 | 107 | # Installshield output folder 108 | [Ee]xpress/ 109 | 110 | # DocProject is a documentation generator add-in 111 | DocProject/buildhelp/ 112 | DocProject/Help/*.HxT 113 | DocProject/Help/*.HxC 114 | DocProject/Help/*.hhc 115 | DocProject/Help/*.hhk 116 | DocProject/Help/*.hhp 117 | DocProject/Help/Html2 118 | DocProject/Help/html 119 | 120 | # Click-Once directory 121 | publish/ 122 | 123 | # Publish Web Output 124 | *.[Pp]ublish.xml 125 | *.azurePubxml 126 | ## TODO: Comment the next line if you want to checkin your 127 | ## web deploy settings but do note that will include unencrypted 128 | ## passwords 129 | #*.pubxml 130 | 131 | # NuGet Packages Directory 132 | packages/* 133 | ## TODO: If the tool you use requires repositories.config 134 | ## uncomment the next line 135 | #!packages/repositories.config 136 | 137 | # Enable "build/" folder in the NuGet Packages folder since 138 | # NuGet packages use it for MSBuild targets. 139 | # This line needs to be after the ignore of the build folder 140 | # (and the packages folder if the line above has been uncommented) 141 | !packages/build/ 142 | 143 | # Windows Azure Build Output 144 | csx/ 145 | *.build.csdef 146 | 147 | # Windows Store app package directory 148 | AppPackages/ 149 | 150 | # Others 151 | sql/ 152 | *.Cache 153 | ClientBin/ 154 | [Ss]tyle[Cc]op.* 155 | ~$* 156 | *~ 157 | *.dbmdl 158 | *.dbproj.schemaview 159 | *.pfx 160 | *.publishsettings 161 | node_modules/ 162 | 163 | # RIA/Silverlight projects 164 | Generated_Code/ 165 | 166 | # Backup & report files from converting an old project file 167 | # to a newer Visual Studio version. Backup files are not needed, 168 | # because we have git ;-) 169 | _UpgradeReport_Files/ 170 | Backup*/ 171 | UpgradeLog*.XML 172 | UpgradeLog*.htm 173 | 174 | # SQL Server files 175 | *.mdf 176 | *.ldf 177 | 178 | # Business Intelligence projects 179 | *.rdl.data 180 | *.bim.layout 181 | *.bim_*.settings 182 | 183 | # Microsoft Fakes 184 | FakesAssemblies/ 185 | 186 | # LightSwitch generated files 187 | GeneratedArtifacts/ 188 | _Pvt_Extensions/ 189 | ModelManifest.xml 190 | /.vs/ 191 | -------------------------------------------------------------------------------- /BitcoinTransactionTool.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BitcoinTransactionTool", "BitcoinTransactionTool\BitcoinTransactionTool.csproj", "{0BD41339-E736-48B1-9BA4-64DB464E954D}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonLibrary", "CommonLibrary\CommonLibrary.csproj", "{3C4402E4-D931-4996-86FB-55FF6F9E7EBD}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {0BD41339-E736-48B1-9BA4-64DB464E954D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {0BD41339-E736-48B1-9BA4-64DB464E954D}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {0BD41339-E736-48B1-9BA4-64DB464E954D}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {0BD41339-E736-48B1-9BA4-64DB464E954D}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {3C4402E4-D931-4996-86FB-55FF6F9E7EBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {3C4402E4-D931-4996-86FB-55FF6F9E7EBD}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {3C4402E4-D931-4996-86FB-55FF6F9E7EBD}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {3C4402E4-D931-4996-86FB-55FF6F9E7EBD}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/App.xaml: -------------------------------------------------------------------------------- 1 |  8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/App.xaml.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using System.Windows; 7 | using System.Windows.Threading; 8 | 9 | namespace BitcoinTransactionTool 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | private void Application_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) 17 | { 18 | MessageBox.Show($"An unhandled catastrophic exception was thrown:\n{e.Exception.Message}", 19 | "Handling Exception in App.xaml", MessageBoxButton.OK, MessageBoxImage.Warning); 20 | e.Handled = true; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/ITransaction.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts; 7 | 8 | namespace BitcoinTransactionTool.Backend.Blockchain 9 | { 10 | public interface ITransaction : IDeserializable 11 | { 12 | TxIn[] TxInList { get; set; } 13 | TxOut[] TxOutList { get; set; } 14 | IWitnessScript[] WitnessList { get; set; } 15 | 16 | 17 | byte[] GetTransactionHash(); 18 | //byte[] GetBytesToSign(ITransaction prevTx, int index, SigHashType sigHashType); 19 | //void WriteScriptSig(Signature sig, PublicKey pubKey, ITransaction prevTx, int index); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Outpoint.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using System; 7 | using System.Linq; 8 | 9 | namespace BitcoinTransactionTool.Backend.Blockchain 10 | { 11 | public class Outpoint : IDeserializable 12 | { 13 | /// 14 | /// Initializes a new instance of using parameters of the . 15 | /// 16 | /// 17 | /// Coin to use 18 | public Outpoint() 19 | { 20 | reverseTxId = true; 21 | HashSize = 32; 22 | Size = sizeof(uint) + HashSize; 23 | } 24 | 25 | /// 26 | /// Initializes a new instance of using given parameters. 27 | /// 28 | /// 29 | /// 30 | /// Hash of the transaction that is being spent as returned by the hash function (no reversal). 31 | /// Index of transaction. 32 | public Outpoint(byte[] hash, uint index) 33 | { 34 | if (hash == null) 35 | throw new ArgumentNullException(nameof(hash), "Transaction hash can not be null."); 36 | if (hash.Length != 32) 37 | throw new ArgumentOutOfRangeException(nameof(hash), $"Transaction hash must be 32 bytes."); 38 | 39 | TxHash = hash.CloneByteArray(); 40 | Index = index; 41 | 42 | reverseTxId = true; 43 | HashSize = 32; 44 | Size = sizeof(uint) + HashSize; 45 | } 46 | 47 | 48 | 49 | public byte[] TxHash { get; set; } 50 | public uint Index { get; set; } 51 | 52 | internal readonly int HashSize; 53 | internal readonly int Size; 54 | private readonly bool reverseTxId; 55 | 56 | 57 | 58 | /// 59 | /// Returns transaction ID of this in base-16. 60 | /// 61 | /// 62 | /// Base-16 encoded transaction ID. 63 | public string GetTxId() 64 | { 65 | if (TxHash == null) 66 | throw new ArgumentNullException(nameof(TxHash), "Transaction hash can not be null"); 67 | 68 | return reverseTxId ? TxHash.Reverse().ToArray().ToBase16() : TxHash.ToBase16(); 69 | } 70 | 71 | 72 | /// 73 | /// Converts this instance into its byte array representation. 74 | /// 75 | /// 76 | /// An array of bytes. 77 | public byte[] Serialize() 78 | { 79 | if (TxHash == null) 80 | throw new ArgumentNullException(nameof(TxHash), "Transaction hash can not be null."); 81 | 82 | return ByteArray.ConcatArrays( 83 | TxHash, 84 | Index.ToByteArray(false) 85 | ); 86 | } 87 | 88 | 89 | /// 90 | /// Deserializes the given byte array starting from the specified offset. The return value indicates success. 91 | /// 92 | /// Byte array containing an . 93 | /// The offset inside the to start from. 94 | /// Error message (null if sucessful, otherwise will contain information about the failure). 95 | /// True if deserialization was successful, false if otherwise. 96 | public bool TryDeserialize(byte[] data, ref int offset, out string error) 97 | { 98 | if (offset < 0) 99 | { 100 | error = "Offset can not be negative."; 101 | return false; 102 | } 103 | if (data == null || data.Length - offset < Size) 104 | { 105 | error = "Data length is not valid."; 106 | return false; 107 | } 108 | 109 | 110 | TxHash = data.SubArray(offset, HashSize); 111 | offset += HashSize; 112 | 113 | Index = data.SubArray(offset, sizeof(uint)).ToUInt32(false); 114 | offset += sizeof(uint); 115 | 116 | error = null; 117 | return true; 118 | } 119 | 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/IPubkeyScript.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts 7 | { 8 | public interface IPubkeyScript : IScript 9 | { 10 | /// 11 | /// Returns type of this pubkey script instance. 12 | /// 13 | /// enum 14 | PubkeyScriptType GetPublicScriptType(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/IRedeemScript.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts 7 | { 8 | public interface IRedeemScript : IScript 9 | { 10 | /// 11 | /// Returns type of this redeem script instance. 12 | /// 13 | /// enum 14 | RedeemScriptType GetRedeemScriptType(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/IScript.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations; 7 | 8 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts 9 | { 10 | public interface IScript : IDeserializable 11 | { 12 | /// 13 | /// Returns whether the script instance is of witness type. It will affect (de)serialization methods. 14 | /// 15 | bool IsWitness { get; } 16 | 17 | /// 18 | /// Type of this script instance 19 | /// 20 | ScriptType ScriptType { get; } 21 | 22 | /// 23 | /// List of operations that the script contains. 24 | /// 25 | IOperation[] OperationList { get; set; } 26 | 27 | /// 28 | /// Converts this instance into its byte array representation only containing s as bytes 29 | /// without the starting integer for length or count. 30 | /// 31 | /// An array of bytes 32 | byte[] ToByteArray(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/ISignatureScript.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts 7 | { 8 | public interface ISignatureScript : IScript 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/IWitnessScript.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts 7 | { 8 | public interface IWitnessScript : IScript 9 | { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/BaseOperation.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations 7 | { 8 | /// 9 | /// Base abstract class for all operations. Implements overrides for Equals() and GetHashCode() functions. 10 | /// 11 | public abstract class BaseOperation : IOperation 12 | { 13 | /// 14 | /// A single byte inticating type of the opeartion 15 | /// 16 | public abstract OP OpValue { get; } 17 | 18 | /// 19 | /// When overriden, performs the specifc operation on the given stack object . 20 | /// 21 | /// Stack to use 22 | /// Error message (null if sucessful, otherwise will contain information about the failure) 23 | /// True if operation was successful, false if otherwise 24 | public abstract bool Run(IOpData opData, out string error); 25 | 26 | /// 27 | /// Determines whether the specified object is equal to the current object. 28 | /// 29 | /// The object to compare with the current object. 30 | /// True if the specified object is equal to the current object, flase if otherwise. 31 | public override bool Equals(object obj) 32 | { 33 | if (obj is IOperation) 34 | { 35 | return ((IOperation)obj).OpValue == OpValue; 36 | } 37 | return false; 38 | } 39 | 40 | /// 41 | /// Returns the hash code for this instance. 42 | /// 43 | /// A 32-bit signed integer hash code 44 | public override int GetHashCode() 45 | { 46 | return OpValue.GetHashCode(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/CheckSigOps.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations 7 | { 8 | public class CheckSigOp : BaseOperation 9 | { 10 | public override OP OpValue => OP.CheckSig; 11 | 12 | public override bool Run(IOpData opData, out string error) 13 | { 14 | if (opData.ItemCount < 2) 15 | { 16 | error = "Invalid number of elements in stack."; 17 | return false; 18 | } 19 | 20 | byte[] pubBa = opData.Pop(); 21 | byte[] sigBa = opData.Pop(); 22 | 23 | // "fake" pass! 24 | opData.Push(new byte[] { 1 }); 25 | 26 | error = null; 27 | return true; 28 | } 29 | } 30 | 31 | public class CheckSigVerifyOp : BaseOperation 32 | { 33 | public override OP OpValue => OP.CheckSigVerify; 34 | 35 | public override bool Run(IOpData opData, out string error) 36 | { 37 | IOperation cs = new CheckSigOp(); 38 | IOperation ver = new VerifyOp(); 39 | 40 | if (!cs.Run(opData, out error)) 41 | { 42 | return false; 43 | } 44 | 45 | return ver.Run(opData, out error); 46 | } 47 | } 48 | 49 | public class CheckMultiSigOp : BaseOperation 50 | { 51 | public override OP OpValue => OP.CheckMultiSig; 52 | 53 | public override bool Run(IOpData opData, out string error) 54 | { 55 | error = null; 56 | return true; // "fake" pass 57 | } 58 | } 59 | 60 | public class CheckMultiSigVerifyOp : BaseOperation 61 | { 62 | public override OP OpValue => OP.CheckMultiSigVerify; 63 | 64 | public override bool Run(IOpData opData, out string error) 65 | { 66 | IOperation cms = new CheckMultiSigOp(); 67 | IOperation ver = new VerifyOp(); 68 | 69 | if (!cms.Run(opData, out error)) 70 | { 71 | return false; 72 | } 73 | 74 | return ver.Run(opData, out error); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/CryptoOps.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend.Cryptography.Hashing; 7 | 8 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations 9 | { 10 | /// 11 | /// Base (abstract) class for cryptography operations. Implements and 12 | /// . Derived classes must set the property. 13 | /// 14 | public abstract class CryptoOp : BaseOperation 15 | { 16 | protected abstract IHashFunction Hash { get; } 17 | 18 | /// 19 | /// Replaces top stack item with its hash digest. Return value indicates success. 20 | /// 21 | /// Data to use 22 | /// Error message (null if sucessful, otherwise will contain information about the failure) 23 | /// True if operation was successful, false if otherwise 24 | public override bool Run(IOpData opData, out string error) 25 | { 26 | if (opData.ItemCount < 1) 27 | { 28 | error = "Not enough items in stack."; 29 | return false; 30 | } 31 | 32 | opData.Push(Hash.ComputeHash(opData.Pop())); 33 | 34 | error = null; 35 | return true; 36 | } 37 | } 38 | 39 | 40 | 41 | /// 42 | /// Operation to perform RIPEMD-160 hash on top stack item. 43 | /// 44 | public class RipeMd160Op : CryptoOp 45 | { 46 | public sealed override OP OpValue => OP.RIPEMD160; 47 | protected sealed override IHashFunction Hash => new Ripemd160(); 48 | } 49 | 50 | 51 | /// 52 | /// Operation to perform SHA-1 hash on top stack item. 53 | /// 54 | public class Sha1Op : CryptoOp 55 | { 56 | public sealed override OP OpValue => OP.SHA1; 57 | protected sealed override IHashFunction Hash => new Sha1(); 58 | } 59 | 60 | 61 | /// 62 | /// Operation to perform SHA-256 hash on top stack item. 63 | /// 64 | public class Sha256Op : CryptoOp 65 | { 66 | public sealed override OP OpValue => OP.SHA256; 67 | protected sealed override IHashFunction Hash => new Sha256(false); 68 | } 69 | 70 | 71 | /// 72 | /// Operation to perform SHA-256 then RIPEMD-160 hash on top stack item. 73 | /// 74 | public class Hash160Op : CryptoOp 75 | { 76 | public sealed override OP OpValue => OP.HASH160; 77 | protected sealed override IHashFunction Hash => new Ripemd160Sha256(); 78 | } 79 | 80 | 81 | /// 82 | /// Operation to perform SHA-256 hash twice on top stack item. 83 | /// 84 | public class Hash256Op : CryptoOp 85 | { 86 | public sealed override OP OpValue => OP.HASH256; 87 | protected sealed override IHashFunction Hash => new Sha256(true); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/EqualityOps.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations 7 | { 8 | /// 9 | /// Operation to check equality of top two stack items. 10 | /// 11 | public class EqualOp : BaseOperation 12 | { 13 | public override OP OpValue => OP.EQUAL; 14 | 15 | /// 16 | /// Removes top two stack item and pushes (true for equality and false otherwiwe) onto the stack. Return value indicates success. 17 | /// 18 | /// Data to use 19 | /// Error message (null if sucessful, otherwise will contain information about the failure) 20 | /// True if operation was successful, false if otherwise 21 | public override bool Run(IOpData opData, out string error) 22 | { 23 | if (opData.ItemCount < 2) 24 | { 25 | error = "There was not enough items left in the stack to check."; 26 | return false; 27 | } 28 | 29 | byte[] item1 = opData.Pop(); 30 | byte[] item2 = opData.Pop(); 31 | 32 | if (item1.IsEqualTo(item2)) 33 | { 34 | opData.Push(new byte[] { 1 }); 35 | } 36 | else 37 | { 38 | opData.Push(new byte[0]); 39 | } 40 | 41 | error = null; 42 | return true; 43 | } 44 | } 45 | 46 | 47 | 48 | /// 49 | /// Operation to check and verify equality of top two stack items. 50 | /// 51 | public class EqualVerifyOp : BaseOperation 52 | { 53 | public override OP OpValue => OP.EqualVerify; 54 | 55 | /// 56 | /// Removes top two stack item checks their equality, fails if not equal. Return value indicates success. 57 | /// 58 | /// Data to use 59 | /// Error message (null if sucessful, otherwise will contain information about the failure) 60 | /// True if operation was successful, false if otherwise 61 | public override bool Run(IOpData opData, out string error) 62 | { 63 | if (opData.ItemCount < 2) 64 | { 65 | error = "There was not enough items left in the stack to check."; 66 | return false; 67 | } 68 | 69 | byte[] item1 = opData.Pop(); 70 | byte[] item2 = opData.Pop(); 71 | 72 | if (item1.IsEqualTo(item2)) 73 | { 74 | error = null; 75 | return true; 76 | } 77 | else 78 | { 79 | error = "Items were not equal."; 80 | return false; 81 | } 82 | 83 | // ^^ this way we skip unnecessary OP instantiation and Push() and Pop() operations on IOpData 84 | 85 | //EqualOp eq = new EqualOp(); 86 | //VerifyOp ver = new VerifyOp(); 87 | //if (!eq.Run(opData, out error)) 88 | //{ 89 | // return false; 90 | //} 91 | //return ver.Run(opData, out error); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/IOpData.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations 7 | { 8 | /// 9 | /// For implementing a last-in-first-out (LIFO) collection to be used with s. 10 | /// All indexes are zero based meaning item at the end (real index = length-1) is index 0, 11 | /// the item before last is 1,... the first item (real index=0) is length-1. 12 | /// 13 | public interface IOpData 14 | { 15 | //ICoin Coin { get; } 16 | 17 | /// 18 | /// Returns number of available items in the "stack" 19 | /// 20 | int ItemCount { get; } 21 | 22 | /// 23 | /// Returns the item at the top of the "stack" without removing it. 24 | /// 25 | /// The byte array at the top of the stack 26 | byte[] Peek(); 27 | 28 | /// 29 | /// Returns multiple items from the top of the "stack" without removing them. 30 | /// 31 | /// Number of items to return 32 | /// An array of byte arrays from the top of the stack 33 | byte[][] Peek(int count); 34 | 35 | /// 36 | /// Returns the item at a specific index starting from the top of the "stack" without removing it. 37 | /// NOTE: Index starts from zero meaning the item at the end (length-1) is index 0, the item before end is 1 and so on. 38 | /// 39 | /// Index of item from end to return (starting from 0) 40 | /// The byte array at the specified intex 41 | byte[] PeekAtIndex(int index); 42 | 43 | /// 44 | /// Removes and returns the item at the top of the "stack". 45 | /// 46 | /// The removed byte array at the top of the stack 47 | byte[] Pop(); 48 | 49 | /// 50 | /// Removes multiple items from the top of the stack and returns all of them without changing the order ([1234] -> [34]). 51 | /// 52 | /// Number of items to remove and return 53 | /// An array of byte arrays removed from the top of the stack 54 | byte[][] Pop(int count); 55 | 56 | /// 57 | /// Removes and returns the item at the specified index (will shift the items in its place). 58 | /// NOTE: Index starts from zero meaning the item at the end (length-1) is index 0, the item before end is 1 and so on. 59 | /// 60 | /// 61 | /// The byte array removed from the specified intex 62 | byte[] PopAtIndex(int index); 63 | 64 | /// 65 | /// Pushes (or inserts) an item at the top of the "stack". 66 | /// 67 | /// Byte array to push onto the "stack" 68 | void Push(byte[] data); 69 | 70 | /// 71 | /// Pushes (or inserts) multiple items at the top of the "stack" in the same order. 72 | /// 73 | /// Arrays of byte array to push 74 | void Push(byte[][] data); 75 | 76 | /// 77 | /// Inserts an item at the specified index (from the top) of the "stack". 78 | /// NOTE: Index starts from zero meaning the item at the end (length-1) is index 0, the item before end is 1 and so on. 79 | /// 80 | /// Byte array to insert in the "stack" 81 | /// Index at which to insert the 82 | void Insert(byte[] data, int index); 83 | 84 | /// 85 | /// Inserts multiple items at the specified index (from the top) of the "stack". 86 | /// NOTE: Index starts from zero meaning the item at the end (length-1) is index 0, the item before end is 1 and so on. 87 | /// 88 | /// Array of Byte arrays to insert in the "stack" 89 | /// Index at which to insert the 90 | void Insert(byte[][] data, int index); 91 | 92 | 93 | /// 94 | /// Returns number of available items in the "alt-stack" 95 | /// 96 | int AltItemCount { get; } 97 | 98 | /// 99 | /// Removes and returns the item at the top of the "alt-stack". 100 | /// 101 | /// The removed byte array at the top of the "alt-stack" 102 | byte[] AltPop(); 103 | 104 | /// 105 | /// Pushes (or inserts) an item at the top of the "alt-stack". 106 | /// 107 | /// Byte array to push onto the "alt-stack" 108 | void AltPush(byte[] data); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/IOperation.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations 7 | { 8 | /// 9 | /// Defines any kind of operation that is placed inside s and could be run. 10 | /// 11 | public interface IOperation 12 | { 13 | /// 14 | /// A single byte inticating type of the opeartion 15 | /// 16 | OP OpValue { get; } 17 | 18 | /// 19 | /// Performs the action defined by the operation on the stack. Return value indicates success. 20 | /// 21 | /// Data used by the s (an advanced form of ) 22 | /// Error message (null if sucessful, otherwise will contain information about the failure) 23 | /// True if operation was successful, false if otherwise 24 | bool Run(IOpData opData, out string error); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/LockTimeOps.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations 7 | { 8 | public abstract class LockTimeOp : BaseOperation 9 | { 10 | /// 11 | /// The locktime value converted from the top stack item (without popping it) 12 | /// 13 | protected long lt; 14 | 15 | protected bool TrySetLockTime(IOpData opData, out string error) 16 | { 17 | if (opData.ItemCount < 1) 18 | { 19 | error = "Not enough items left in the stack."; 20 | return false; 21 | } 22 | 23 | // The two locktime OPs (CheckLocktimeVerify and CheckSequenceVerify) used to be NOPs. NOPs don't do anything. 24 | // For backward compatibility of the softfork, Run Peeks at the top item of the stack instead of Poping it. 25 | byte[] data = opData.Peek(); 26 | 27 | // TODO: move this check to OpHelper 28 | // (for locktimes max length is 5 for others it is 4) 29 | if (data.Length > 5) 30 | { 31 | error = "Data length for locktimes can not be bigger than 5."; 32 | return false; 33 | } 34 | 35 | if (!OpHelper.TryConvertByteArrayToInt(data, out lt, true)) 36 | { 37 | error = "Invalid number format."; 38 | return false; 39 | } 40 | 41 | if (lt < 0) 42 | { 43 | error = "Locktime can not be negative."; 44 | return false; 45 | } 46 | 47 | error = null; 48 | return true; 49 | } 50 | } 51 | 52 | 53 | 54 | public class CheckLocktimeVerifyOp : LockTimeOp 55 | { 56 | public override OP OpValue => OP.CheckLocktimeVerify; 57 | 58 | public override bool Run(IOpData opData, out string error) 59 | { 60 | if (!TrySetLockTime(opData, out error)) 61 | { 62 | return false; 63 | } 64 | 65 | // Compare to tx.locktime (we assume it is valid and skip this!) 66 | // TODO: change this for this tool if transactions were set inside IOpdata one day... 67 | 68 | error = null; 69 | return true; 70 | } 71 | } 72 | 73 | 74 | 75 | public class CheckSequenceVerifyOp : LockTimeOp 76 | { 77 | public override OP OpValue => OP.CheckSequenceVerify; 78 | 79 | public override bool Run(IOpData opData, out string error) 80 | { 81 | if (!TrySetLockTime(opData, out error)) 82 | { 83 | return false; 84 | } 85 | 86 | // Compare to tx.locktime, as relative locktime (we assume it is valid and skip this!) 87 | // TODO: change this for this tool if transactions were set inside IOpdata one day... 88 | 89 | error = null; 90 | return true; 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/NotRunableOps.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations 7 | { 8 | /// 9 | /// Base abstract class for operations that can not be run 10 | /// (should fail when is called). 11 | /// Implements a finalized Run() and has overrides for Equals() and GetHashCode() functions from class. 12 | /// 13 | public abstract class NotRunableOps : BaseOperation 14 | { 15 | /// 16 | /// Fails when called. 17 | /// 18 | /// Stack object (won't be used) 19 | /// Error message (contains name of the operation that caused the failure) 20 | /// False (always failing) 21 | public sealed override bool Run(IOpData opData, out string error) 22 | { 23 | error = $"Can not run an OP_{OpValue.ToString()} operation."; 24 | return false; 25 | } 26 | } 27 | 28 | 29 | 30 | // We have an IOperation for OP.Reserved,... because they can exist in a transaction but can not be run. 31 | // We don't have any IOperation for OP.VerIf,... because they can neither exist nor be run. 32 | 33 | 34 | /// 35 | /// Reserved operation, will fail on running. 36 | /// 37 | public class ReservedOp : NotRunableOps 38 | { 39 | public override OP OpValue => OP.Reserved; 40 | } 41 | 42 | /// 43 | /// Removed operation, will fail on running. 44 | /// 45 | public class VEROp : NotRunableOps 46 | { 47 | public override OP OpValue => OP.VER; 48 | } 49 | 50 | /// 51 | /// Reserved operation, will fail on running. 52 | /// 53 | public class Reserved1Op : NotRunableOps 54 | { 55 | public override OP OpValue => OP.Reserved1; 56 | } 57 | 58 | /// 59 | /// Reserved operation, will fail on running. 60 | /// 61 | public class Reserved2Op : NotRunableOps 62 | { 63 | public override OP OpValue => OP.Reserved2; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/OpHelper.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using System; 7 | 8 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations 9 | { 10 | internal static class OpHelper 11 | { 12 | /// 13 | /// Checks whether a given byte array is zero (...,0,0,0,0) or negative zero (...,0,0,0x80) 14 | /// This is the same as IsTrue() 15 | /// 16 | /// Byte array to check 17 | /// True if given bytes represented zero or negative zero; False if otherwise. 18 | internal static bool IsNotZero(byte[] data) 19 | { 20 | for (int i = 0; i < data.Length; i++) 21 | { 22 | if (data[i] != 0) 23 | { 24 | // Can be negative zero 25 | if (i == data.Length - 1 && data[i] == 0x80) 26 | { 27 | return false; 28 | } 29 | return true; 30 | } 31 | } 32 | return false; 33 | } 34 | 35 | 36 | // This method is supposed to convert the bytes that are already in the stack (not in scripts) to a numeric value. 37 | // This method is called by the following methods and each require a specific size of data: 38 | // - ArithmeticOps that need values between(-2^31 +1) and(2^31 -1) (0xffffff7f) => 4 bytes 39 | // - Multisig m of n that needs values between 0 and 20 => 1 byte 40 | // - Locktimes that need values between 0 and(2^39-1) (0xffffffff7f) => 5 bytes 41 | // 42 | // So we choose the biggest type we have(Int64) but the caller is responsible to check if returned value is in range or not. 43 | // 44 | // IsStrict is only there to ensure shortest form was chosen to encode a number: 1 = {1} instead of {1,0,0} 45 | public static bool TryConvertByteArrayToInt(byte[] data, out long result, bool isStrict) 46 | { 47 | result = 0; 48 | if (data == null || data.Length > sizeof(long)) 49 | { 50 | return false; 51 | } 52 | 53 | if (data.Length == 0) 54 | { 55 | return true; 56 | } 57 | 58 | if (isStrict && (data[data.Length - 1] & 0b0111_1111) == 0) 59 | { 60 | if (data.Length <= 1 || (data[data.Length - 2] & 0b1000_0000) == 0) 61 | { 62 | return false; 63 | } 64 | } 65 | 66 | for (int i = 0; i < data.Length; i++) 67 | { 68 | result |= (long)data[i] << (8 * i); 69 | } 70 | 71 | if ((data[data.Length - 1] & 0b1000_0000) != 0) 72 | { 73 | result &= ~(0b1000_0000 << (8 * (data.Length - 1))); 74 | result *= -1; 75 | } 76 | 77 | return true; 78 | } 79 | 80 | 81 | public static byte[] IntToByteArray(long val) 82 | { 83 | if (val == 0) 84 | { 85 | return new byte[0]; 86 | } 87 | 88 | if (val >= 0) 89 | { 90 | byte[] data = val.ToByteArray(false).TrimEnd(); 91 | if ((data[data.Length - 1] & 0b1000_0000) != 0) 92 | { 93 | data = data.AppendToEnd(0); 94 | } 95 | return data; 96 | } 97 | else 98 | { 99 | byte[] data = (-val).ToByteArray(false).TrimEnd(); 100 | if ((data[data.Length - 1] & 0b1000_0000) == 0) 101 | { 102 | data[data.Length - 1] |= 0b1000_0000; 103 | } 104 | else 105 | { 106 | data = data.AppendToEnd(0b1000_0000); 107 | } 108 | return data; 109 | } 110 | } 111 | 112 | 113 | internal static OP IntToOp(int val) 114 | { 115 | if (val == 0) 116 | { 117 | return OP._0; 118 | } 119 | else if (val == -1) 120 | { 121 | return OP.Negative1; 122 | } 123 | else if (val >= 1 && val <= 16) 124 | { 125 | // OP_1 = 0x51, OP_2 = 0x52,... 126 | return (OP)(val + 0x50); 127 | } 128 | else 129 | { 130 | throw new ArgumentOutOfRangeException(nameof(val), "There is no OP defined for values outside of ∈[-1,16]."); 131 | } 132 | } 133 | 134 | 135 | public static bool HasOpNum(byte[] data) 136 | { 137 | if (data.Length == 0) 138 | { 139 | return true; 140 | } 141 | else if (data.Length == 1) 142 | { 143 | if (data[0] == 0b10000000 /*-1*/ || data[0] >= 0 && data[0] <= 16) 144 | { 145 | return true; 146 | } 147 | } 148 | 149 | return false; 150 | } 151 | 152 | internal static bool IsNumberOp(OP val) 153 | { 154 | return !(val != OP._0 && val != OP.Negative1 && val < OP._1 || val > OP._16); 155 | } 156 | 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/ReturnOp.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using System; 7 | 8 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations 9 | { 10 | /// 11 | /// Operation that is used to include an arbitrary data in transactions, it will fail on running. 12 | /// 13 | public class ReturnOp : NotRunableOps 14 | { 15 | /// 16 | /// Initializes a new instance of with an empty data (0x6a). 17 | /// 18 | public ReturnOp() 19 | { 20 | } 21 | 22 | /// 23 | /// Initializes a new instance of using the given data. 24 | /// 25 | /// Data to use (can be null) 26 | /// 27 | /// [Default value = true] 28 | /// If true, the data will be included after using scheme. 29 | /// 30 | public ReturnOp(byte[] ba, bool usePushOp = true) 31 | { 32 | if (ba == null || ba.Length == 0) 33 | { 34 | Data = new byte[1] { (byte)OP.RETURN }; 35 | } 36 | else if (usePushOp) 37 | { 38 | StackInt size = new StackInt(ba.Length); 39 | Data = ByteArray.ConcatArrays( 40 | new byte[1] { (byte)OP.RETURN }, 41 | size.ToByteArray(), 42 | ba); 43 | } 44 | else 45 | { 46 | Data = new byte[ba.Length + 1]; 47 | Data[0] = (byte)OP.RETURN; 48 | Buffer.BlockCopy(ba, 0, Data, 1, ba.Length); 49 | } 50 | } 51 | 52 | /// 53 | /// Initializes a new instance of using the given . 54 | /// 55 | /// 56 | /// Script to use 57 | /// 58 | /// [Default value = true] 59 | /// If true, the data will be included after using scheme. 60 | /// 61 | public ReturnOp(IScript scr, bool usePushOp = true) 62 | { 63 | if (scr == null) 64 | throw new ArgumentNullException(nameof(scr), "Script can not be null."); 65 | 66 | byte[] temp = scr.ToByteArray(); 67 | 68 | if (usePushOp) 69 | { 70 | StackInt size = new StackInt(temp.Length); 71 | Data = ByteArray.ConcatArrays( 72 | new byte[1] { (byte)OP.RETURN }, 73 | size.ToByteArray(), 74 | temp); 75 | } 76 | else 77 | { 78 | Data = new byte[temp.Length + 1]; 79 | Data[0] = (byte)OP.RETURN; 80 | Buffer.BlockCopy(temp, 0, Data, 1, temp.Length); 81 | } 82 | } 83 | 84 | 85 | 86 | // TODO: change accessibility to internal and let test project access it only 87 | public byte[] Data { get; private set; } 88 | 89 | /// 90 | /// A single byte inticating type of the opeartion 91 | /// 92 | public override OP OpValue => OP.RETURN; 93 | 94 | 95 | 96 | /// 97 | /// Returns the byte array representation of this operation based on its type and data. 98 | /// Used by Serialize() methods. 99 | /// 100 | /// An array of bytes 101 | public byte[] ToByteArray() 102 | { 103 | if (Data == null || Data.Length == 0) 104 | { 105 | return new byte[1] { (byte)OP.RETURN }; 106 | } 107 | else 108 | { 109 | return Data.CloneByteArray(); 110 | } 111 | } 112 | 113 | 114 | /// 115 | /// Reads the byte and the following specified data length from the specified offset. 116 | /// The return value indicates success. 117 | /// 118 | /// Byte array to use 119 | /// The offset inside the to start from. 120 | /// Error message (null if sucessful, otherwise will contain information about the failure). 121 | /// 122 | /// Length of the data to read. Must be at least 1 byte, the itself. 123 | /// (note that doesn't have any internal mechanism to tell us how much data it holds, 124 | /// the length is instead specified before as the length of the whole script). 125 | /// 126 | /// True if reading was successful, false if otherwise. 127 | public bool TryRead(byte[] data, ref int offset, out string error, int length) 128 | { 129 | if (offset < 0) 130 | { 131 | error = "Offset can not be negative."; 132 | return false; 133 | } 134 | if (length < 1) 135 | { 136 | error = "Lengh can not be smaller than 1."; 137 | return false; 138 | } 139 | if (data == null || data.Length - offset < length) 140 | { 141 | error = "Data length is not valid."; 142 | return false; 143 | } 144 | if (data[offset] != (byte)OP.RETURN) 145 | { 146 | error = $"OP at offset={offset} is not equal to OP_Return."; 147 | return false; 148 | } 149 | 150 | Data = data.SubArray(offset, length); 151 | offset += length; 152 | 153 | error = null; 154 | return true; 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/SimpleRunableOps.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations 7 | { 8 | /// 9 | /// Base abstract class for operations that don't do anything with the stack. 10 | /// Implements a finalized Run() and has overrides for Equals() and GetHashCode() functions from class. 11 | /// 12 | public abstract class SimpleRunableOps : BaseOperation 13 | { 14 | /// 15 | /// Doesn't do anything. 16 | /// 17 | /// Stack object (won't be used) 18 | /// Error message (always null) 19 | /// True (always successful) 20 | public sealed override bool Run(IOpData opData, out string error) 21 | { 22 | error = null; 23 | return true; 24 | } 25 | } 26 | 27 | 28 | 29 | /// 30 | /// Ignored operation (it doesn't do anything). Could be used for future soft-forks. 31 | /// 32 | public class NOPOp : SimpleRunableOps 33 | { 34 | public override OP OpValue => OP.NOP; 35 | } 36 | 37 | /// 38 | /// Ignored operation (it doesn't do anything). Could be used for future soft-forks. 39 | /// 40 | public class NOP1Op : SimpleRunableOps 41 | { 42 | public override OP OpValue => OP.NOP1; 43 | } 44 | 45 | /// 46 | /// Ignored operation (it doesn't do anything). Could be used for future soft-forks. 47 | /// 48 | public class NOP4Op : SimpleRunableOps 49 | { 50 | public override OP OpValue => OP.NOP4; 51 | } 52 | 53 | /// 54 | /// Ignored operation (it doesn't do anything). Could be used for future soft-forks. 55 | /// 56 | public class NOP5Op : SimpleRunableOps 57 | { 58 | public override OP OpValue => OP.NOP5; 59 | } 60 | 61 | /// 62 | /// Ignored operation (it doesn't do anything). Could be used for future soft-forks. 63 | /// 64 | public class NOP6Op : SimpleRunableOps 65 | { 66 | public override OP OpValue => OP.NOP6; 67 | } 68 | 69 | /// 70 | /// Ignored operation (it doesn't do anything). Could be used for future soft-forks. 71 | /// 72 | public class NOP7Op : SimpleRunableOps 73 | { 74 | public override OP OpValue => OP.NOP7; 75 | } 76 | 77 | /// 78 | /// Ignored operation (it doesn't do anything). Could be used for future soft-forks. 79 | /// 80 | public class NOP8Op : SimpleRunableOps 81 | { 82 | public override OP OpValue => OP.NOP8; 83 | } 84 | 85 | /// 86 | /// Ignored operation (it doesn't do anything). Could be used for future soft-forks. 87 | /// 88 | public class NOP9Op : SimpleRunableOps 89 | { 90 | public override OP OpValue => OP.NOP9; 91 | } 92 | 93 | /// 94 | /// Ignored operation (it doesn't do anything). Could be used for future soft-forks. 95 | /// 96 | public class NOP10Op : SimpleRunableOps 97 | { 98 | public override OP OpValue => OP.NOP10; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/SizeOp.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations 7 | { 8 | /// 9 | /// Operation to push the size of the top stack item to the stack. 10 | /// 11 | public class SizeOp : IOperation 12 | { 13 | public OP OpValue => OP.SIZE; 14 | 15 | /// 16 | /// Pushes the size of the top stack item to the stack. Return value indicates success. 17 | /// 18 | /// Data to use 19 | /// Error message (null if sucessful, otherwise will contain information about the failure) 20 | /// True if operation was successful, false if otherwise 21 | public bool Run(IOpData opData, out string error) 22 | { 23 | if (opData.ItemCount < 1) 24 | { 25 | error = "There was not enough items left in the stack."; 26 | return false; 27 | } 28 | 29 | byte[] temp = opData.Peek(); 30 | opData.Push(OpHelper.IntToByteArray(temp.Length)); 31 | 32 | error = null; 33 | return true; 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/Operations/VerifyOp.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations 7 | { 8 | /// 9 | /// Operation to verify if the top stack item is true. 10 | /// 11 | public class VerifyOp : BaseOperation 12 | { 13 | public override OP OpValue => OP.VERIFY; 14 | 15 | /// 16 | /// Removes top stack item only passes if it is true. Return value indicates success. 17 | /// 18 | /// Data to use 19 | /// Error message (null if sucessful, otherwise will contain information about the failure) 20 | /// True if operation was successful, false if otherwise 21 | public override bool Run(IOpData opData, out string error) 22 | { 23 | if (opData.ItemCount < 1) 24 | { 25 | error = "There was not enough items left in the stack."; 26 | return false; 27 | } 28 | // Check the top stack value, only fail if False 29 | bool b = OpHelper.IsNotZero(opData.Pop()); 30 | if (!b) 31 | { 32 | error = "Top stack item value was 'false'."; 33 | return false; 34 | } 35 | 36 | error = null; 37 | return true; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/RedeemScript.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations; 7 | using BitcoinTransactionTool.Backend.Cryptography.Hashing; 8 | using System; 9 | 10 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts 11 | { 12 | public class RedeemScript : Script, IRedeemScript 13 | { 14 | public RedeemScript() 15 | { 16 | IsWitness = false; 17 | OperationList = new IOperation[0]; 18 | ScriptType = ScriptType.ScriptRedeem; 19 | hashFunc = new Ripemd160Sha256() /*coin.AddressHashFunction*/; 20 | 21 | witHashFunc = new Sha256(false); // TODO: set this field in ICoin 22 | maxLenOrCount = 10000; // TODO: set this to a real value and from ICoin 23 | } 24 | 25 | 26 | 27 | private IHashFunction hashFunc; 28 | private IHashFunction witHashFunc; 29 | 30 | 31 | 32 | public RedeemScriptType GetRedeemScriptType() 33 | { 34 | if (OperationList == null || OperationList.Length == 0) 35 | { 36 | return RedeemScriptType.Empty; 37 | } 38 | else if (OperationList.Length == 2 && 39 | OperationList[0] is PushDataOp && OperationList[0].OpValue == OP._0 && 40 | OperationList[1] is PushDataOp && ((PushDataOp)OperationList[1]).data.Length == hashFunc.HashByteSize) 41 | { 42 | return RedeemScriptType.P2SH_P2WPKH; 43 | } 44 | else if (OperationList.Length == 2 && 45 | OperationList[0] is PushDataOp && OperationList[0].OpValue == OP._0 && 46 | OperationList[1] is PushDataOp && ((PushDataOp)OperationList[1]).data.Length == witHashFunc.HashByteSize) 47 | { 48 | return RedeemScriptType.P2SH_P2WSH; 49 | } 50 | 51 | return RedeemScriptType.Unknown; 52 | } 53 | 54 | //public void SetToMultiSig(int m, int n, Tuple[] pubKeyList) 55 | //{ 56 | // if (m < 1 || m > 16 || m > n) 57 | // throw new ArgumentOutOfRangeException(nameof(m), "M must be between 1 and 16 and smaller than N."); 58 | // if (n < 1 || n > 16) 59 | // throw new ArgumentOutOfRangeException(nameof(n), "N must be between 1 and 16."); 60 | // if (pubKeyList == null || pubKeyList.Length == 0) 61 | // throw new ArgumentNullException(nameof(pubKeyList), "Pubkey list can not be null or empty."); 62 | // if (pubKeyList.Length != n) 63 | // throw new ArgumentOutOfRangeException(nameof(pubKeyList), $"Pubkey list must contain N (={n}) items."); 64 | 65 | // OperationList = new IOperation[n + 3]; // OP_m | pub1 | pub2 | ... | pub(n) | OP_n | OP_CheckMultiSig 66 | // OperationList[0] = new PushDataOp(m); 67 | // OperationList[n + 1] = new PushDataOp(n); 68 | // OperationList[n + 2] = new CheckMultiSigOp(); 69 | // int i = 1; 70 | // foreach (var item in pubKeyList) 71 | // { 72 | // OperationList[i++] = new PushDataOp(item.Item1.ToByteArray(item.Item2)); 73 | // } 74 | //} 75 | 76 | //public void SetToP2SH_P2WPKH(PublicKey pubKey) 77 | //{ 78 | // byte[] hash = hashFunc.ComputeHash(pubKey.ToByteArray(true)); // Always use compressed 79 | // OperationList = new IOperation[] 80 | // { 81 | // new PushDataOp(OP._0), 82 | // new PushDataOp(hash) 83 | // }; 84 | //} 85 | 86 | public void SetToP2SH_P2WSH(Script witnessScript) 87 | { 88 | byte[] hash = witHashFunc.ComputeHash(witnessScript.ToByteArray()); 89 | OperationList = new IOperation[] 90 | { 91 | new PushDataOp(OP._0), 92 | new PushDataOp(hash) 93 | }; 94 | } 95 | 96 | //public void SetToCheckLocktimeVerify(PublicKey pubKey, bool compressed, LockTime lt) 97 | //{ 98 | // OperationList = new IOperation[] 99 | // { 100 | // // TODO: change this to a better return type that doesn't have zeros 101 | // new PushDataOp(lt.ToByteArray(false).TrimEnd()), 102 | // new CheckLocktimeVerifyOp(), 103 | // new DROPOp(), 104 | // new PushDataOp(pubKey.ToByteArray(compressed)), 105 | // new CheckSigOp() 106 | // }; 107 | //} 108 | 109 | public PubkeyScript ConvertP2WPKH_to_P2PKH() 110 | { 111 | if (GetRedeemScriptType() != RedeemScriptType.P2SH_P2WPKH) 112 | { 113 | throw new ArgumentException("This conversion only works for P2SH-P2WPKH redeem script types."); 114 | } 115 | IOperation pushHash = OperationList[1]; 116 | 117 | PubkeyScript res = new PubkeyScript() 118 | { 119 | OperationList = new IOperation[] 120 | { 121 | new DUPOp(), 122 | new Hash160Op(), 123 | pushHash, 124 | new EqualVerifyOp(), 125 | new CheckSigOp() 126 | }, 127 | }; 128 | 129 | res.hashFunc = hashFunc; 130 | res.witHashFunc = witHashFunc; 131 | 132 | return res; 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/ScriptTypeEnums.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts 7 | { 8 | /// 9 | /// Defined script types by 10 | /// , , , 11 | /// classes 12 | /// 13 | public enum ScriptType 14 | { 15 | /// 16 | /// Unknown script type 17 | /// 18 | Unknown, 19 | /// 20 | /// Public key script used in 21 | /// 22 | ScriptPub, 23 | /// 24 | /// Signature script used in 25 | /// 26 | ScriptSig, 27 | /// 28 | /// Redeem script used in 29 | /// 30 | ScriptRedeem, 31 | /// 32 | /// Witness script used in 33 | /// 34 | ScriptWitness, 35 | } 36 | 37 | 38 | /// 39 | /// Defined script types in 40 | /// 41 | public enum PubkeyScriptType 42 | { 43 | /// 44 | /// An empty instance 45 | /// 46 | Empty, 47 | /// 48 | /// Unknown or undefined script type 49 | /// 50 | Unknown, 51 | /// 52 | /// "Pay to public key" public script 53 | /// 54 | P2PK, 55 | /// 56 | /// "Pay to public key hash" public script 57 | /// 58 | P2PKH, 59 | /// 60 | /// "Pay to script hash" public script 61 | /// 62 | P2SH, 63 | /// 64 | /// "Pay to multi-sig" public script 65 | /// 66 | P2MS, 67 | /// 68 | /// public script 69 | /// 70 | CheckLocktimeVerify, 71 | /// 72 | /// public script 73 | /// 74 | RETURN, 75 | /// 76 | /// "Pay to witness public key hash" public script 77 | /// 78 | P2WPKH, 79 | /// 80 | /// "Pay to witness script hash" public script 81 | /// 82 | P2WSH 83 | } 84 | 85 | 86 | /// 87 | /// Defined script types in 88 | /// 89 | public enum RedeemScriptType 90 | { 91 | /// 92 | /// An empty instance 93 | /// 94 | Empty, 95 | /// 96 | /// Unknown or undefined script type 97 | /// 98 | Unknown, 99 | /// 100 | /// Redeem script for m of n multi-signature scripts 101 | /// 102 | MultiSig, 103 | /// 104 | /// Redeem script for scripts 105 | /// 106 | CheckLocktimeVerify, 107 | /// 108 | /// Redeem script for "pay to witness pubkey hash in a pay to script hash" scripts 109 | /// 110 | P2SH_P2WPKH, 111 | /// 112 | /// Redeem script for "pay to witness script hash in a pay to script hash" scripts 113 | /// 114 | P2SH_P2WSH, 115 | /// 116 | /// Redeem script for "pay to witness script hash" scripts 117 | /// 118 | P2WSH, 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/Scripts/WitnessScript.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations; 7 | 8 | namespace BitcoinTransactionTool.Backend.Blockchain.Scripts 9 | { 10 | /// 11 | /// Witness is not actually a script but items inside of the script. 12 | /// 13 | public class WitnessScript : Script, IWitnessScript 14 | { 15 | public WitnessScript() 16 | { 17 | IsWitness = true; 18 | OperationList = new IOperation[0]; 19 | ScriptType = ScriptType.ScriptWitness; 20 | maxLenOrCount = 100; // TODO: set this to a real value and from ICoin 21 | } 22 | 23 | 24 | 25 | //public void SetToP2WPKH(Signature sig, PublicKey pubKey) 26 | //{ 27 | // byte[] sigBa = sig.EncodeWithSigHashType(); 28 | // byte[] pubkBa = pubKey.ToByteArray(true); // only compressed pubkeys are used in witness 29 | 30 | // OperationList = new IOperation[] 31 | // { 32 | // new PushDataOp(sigBa), 33 | // new PushDataOp(pubkBa) 34 | // }; 35 | //} 36 | 37 | //public void SetToP2WSH_MultiSig(Signature[] sigs, RedeemScript redeem) 38 | //{ 39 | // OperationList = new IOperation[sigs.Length + 2]; // OP_0 | Sig1 | sig2 | .... | sig(n) | redeemScript 40 | 41 | // OperationList[0] = new PushDataOp(OP._0); 42 | 43 | // for (int i = 1; i <= sigs.Length; i++) 44 | // { 45 | // OperationList[i] = new PushDataOp(sigs[i].EncodeWithSigHashType()); 46 | // } 47 | 48 | // OperationList[OperationList.Length - 1] = new PushDataOp(new PushDataOp(redeem.ToByteArray()).ToByteArray(false)); 49 | //} 50 | 51 | 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/TxIn.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts; 7 | using System; 8 | 9 | namespace BitcoinTransactionTool.Backend.Blockchain 10 | { 11 | public class TxIn : IDeserializable 12 | { 13 | /// 14 | /// Initializes a new instance of using parameters of the . 15 | /// 16 | public TxIn() 17 | { 18 | SetFields(); 19 | Outpoint = new Outpoint(); 20 | SigScript = new SignatureScript(); 21 | } 22 | 23 | /// 24 | /// Initializes a new instance of using given parameters. 25 | /// 26 | /// 27 | /// Transaction output 28 | /// Signature script 29 | /// Sequence 30 | public TxIn(Outpoint op, SignatureScript sigScript, uint seq) 31 | { 32 | SetFields(); 33 | if (op == null) 34 | throw new ArgumentNullException(nameof(op), "Outpoint can not be null!"); 35 | if (sigScript == null) 36 | throw new ArgumentNullException(nameof(sigScript), "Signature script can not be null!"); 37 | 38 | Outpoint = op; 39 | SigScript = sigScript; 40 | Sequence = seq; 41 | } 42 | 43 | 44 | 45 | public Outpoint Outpoint { get; set; } 46 | public ISignatureScript SigScript { get; set; } 47 | // TODO: read this about sequence and probably create a new variable type for it: 48 | // https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki 49 | public uint Sequence { get; set; } 50 | 51 | internal int MinSize; 52 | internal int MaxSize; 53 | 54 | 55 | 56 | private void SetFields() 57 | { 58 | CompactInt temp = new CompactInt(10000 /*coin.ScriptSigMaxLength*/); 59 | int opSize = new Outpoint().Size; 60 | MinSize = opSize + 1 + 0 + sizeof(uint); 61 | MaxSize = opSize + temp.ToByteArray().Length + 10000 + sizeof(uint); 62 | } 63 | 64 | 65 | /// 66 | /// Converts this instance into its byte array representation. 67 | /// 68 | /// 69 | /// An array of bytes 70 | public byte[] Serialize() 71 | { 72 | if (Outpoint == null) 73 | throw new ArgumentNullException(nameof(Outpoint), "Outpoint can not be null."); 74 | if (SigScript == null) 75 | throw new ArgumentNullException(nameof(SigScript), "Signature script can not be null!"); 76 | 77 | 78 | return ByteArray.ConcatArrays( 79 | Outpoint.Serialize(), 80 | SigScript.Serialize(), 81 | Sequence.ToByteArray(false) 82 | ); 83 | } 84 | 85 | 86 | 87 | /// 88 | /// Deserializes the given byte array starting from the specified offset. The return value indicates success. 89 | /// 90 | /// Byte array containing an . 91 | /// The offset inside the to start from. 92 | /// Error message (null if sucessful, otherwise will contain information about the failure). 93 | /// True if deserialization was successful, false if otherwise. 94 | public bool TryDeserialize(byte[] data, ref int offset, out string error) 95 | { 96 | if (offset < 0) 97 | { 98 | error = "Offset can not be negative."; 99 | return false; 100 | } 101 | if (data == null || data.Length - offset < MinSize) 102 | { 103 | error = "Data length is not valid."; 104 | return false; 105 | } 106 | // TODO: Outpoint and SigScript could be null, perform a check? 107 | 108 | if (!Outpoint.TryDeserialize(data, ref offset, out error)) 109 | { 110 | return false; 111 | } 112 | 113 | if (!SigScript.TryDeserialize(data, ref offset, out error)) 114 | { 115 | return false; 116 | } 117 | 118 | Sequence = data.SubArray(offset, sizeof(uint)).ToUInt32(false); 119 | offset += sizeof(uint); 120 | 121 | error = null; 122 | return true; 123 | } 124 | 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Blockchain/TxOut.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts; 7 | using System; 8 | 9 | namespace BitcoinTransactionTool.Backend.Blockchain 10 | { 11 | public class TxOut : IDeserializable 12 | { 13 | /// 14 | /// Initializes a new instance of using given parameters of the . 15 | /// 16 | public TxOut() 17 | { 18 | PubScript = new PubkeyScript(); 19 | maxAmount = 21_000_000_0000_0000; 20 | } 21 | 22 | /// 23 | /// Initializes a new instance of using given parameters. 24 | /// 25 | /// 26 | /// 27 | /// Payment amount in coin's smallest unit (eg. Satoshi). 28 | /// Public key script 29 | public TxOut(ulong amount, PubkeyScript pkScript) 30 | { 31 | if (amount > 21_000_000_0000_0000) 32 | throw new ArgumentOutOfRangeException(nameof(amount), "Can not spend more than coin's maximum supply."); 33 | if (pkScript == null) 34 | throw new ArgumentNullException(nameof(pkScript), $"Pubkey script can not be null."); 35 | 36 | Amount = amount; 37 | PubScript = pkScript; 38 | 39 | maxAmount = 21_000_000_0000_0000; 40 | } 41 | 42 | 43 | 44 | /// 45 | /// Minimum size of a TxOut. Amount(8) + CompactInt(1) + Script(0) 46 | /// 47 | internal int MinSize = sizeof(ulong) + 1; 48 | private readonly ulong maxAmount; 49 | 50 | public ulong Amount { get; set; } 51 | public IPubkeyScript PubScript { get; set; } 52 | 53 | 54 | /// 55 | /// Converts this instance into its byte array representation. 56 | /// 57 | /// 58 | /// 59 | /// An array of bytes. 60 | public byte[] Serialize() 61 | { 62 | if (PubScript == null) 63 | throw new ArgumentNullException(nameof(PubScript), $"PubKey script can not be null."); 64 | if (Amount > maxAmount) 65 | throw new ArgumentOutOfRangeException(nameof(Amount), "Can not spend more than coin's maximum supply."); 66 | 67 | 68 | return ByteArray.ConcatArrays( 69 | Amount.ToByteArray(false), 70 | PubScript.Serialize() 71 | ); 72 | } 73 | 74 | 75 | /// 76 | /// Deserializes the given byte array starting from the specified offset. The return value indicates success. 77 | /// 78 | /// Byte array containing a . 79 | /// The offset inside the to start from. 80 | /// Error message (null if sucessful, otherwise will contain information about the failure). 81 | /// True if deserialization was successful, false if otherwise. 82 | public bool TryDeserialize(byte[] data, ref int offset, out string error) 83 | { 84 | if (offset < 0) 85 | { 86 | error = "Offset can not be negative."; 87 | return false; 88 | } 89 | if (data == null || data.Length - offset < MinSize) 90 | { 91 | error = "Data length is not valid."; 92 | return false; 93 | } 94 | 95 | 96 | Amount = data.SubArray(offset, 8).ToUInt64(false); 97 | offset += 8; 98 | if (Amount > maxAmount) 99 | { 100 | error = "Amout exceeds maximum coin's supply."; 101 | return false; 102 | } 103 | 104 | if (!PubScript.TryDeserialize(data, ref offset, out error)) 105 | { 106 | return false; 107 | } 108 | 109 | error = null; 110 | return true; 111 | } 112 | 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Constants.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Backend 7 | { 8 | public struct Constants 9 | { 10 | public const decimal Satoshi = 0.00000001m; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Cryptography/Hashing/IHashFunction.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using System; 7 | 8 | namespace BitcoinTransactionTool.Backend.Cryptography.Hashing 9 | { 10 | public interface IHashFunction : IDisposable 11 | { 12 | /// 13 | /// Indicates whether the hash function should be performed twice on message. 14 | /// For example Double SHA256 that bitcoin uses. 15 | /// 16 | bool IsDouble { get; set; } 17 | 18 | /// 19 | /// Size of the hash result in bytes. 20 | /// 21 | int HashByteSize { get; } 22 | 23 | /// 24 | /// Size of the blocks used in each round. 25 | /// 26 | int BlockByteSize { get; } 27 | 28 | /// 29 | /// Computes the hash value for the specified byte array. 30 | /// 31 | /// The byte array to compute hash for 32 | /// The computed hash 33 | byte[] ComputeHash(byte[] data); 34 | 35 | /// 36 | /// Computes the hash value for the specified region of the specified byte array. 37 | /// 38 | /// The byte array to compute hash for 39 | /// The offset into the byte array from which to begin using data. 40 | /// The number of bytes in the array to use as data. 41 | /// The computed hash 42 | byte[] ComputeHash(byte[] buffer, int offset, int count); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Cryptography/Hashing/Sha1.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using System; 7 | using System.Security.Cryptography; 8 | 9 | namespace BitcoinTransactionTool.Backend.Cryptography.Hashing 10 | { 11 | /// 12 | /// This is a wrapper around .Net SHA1 implementation. 13 | /// 14 | public class Sha1 : IHashFunction 15 | { 16 | /// 17 | /// Initializes a new instance of the . 18 | /// 19 | /// Determines whether the hash should be performed twice. 20 | public Sha1(bool isDouble = false) 21 | { 22 | IsDouble = isDouble; 23 | } 24 | 25 | 26 | 27 | /// 28 | /// Indicates whether the hash function should be performed twice on message. 29 | /// For example Double SHA256 that bitcoin uses. 30 | /// 31 | public bool IsDouble { get; set; } 32 | 33 | /// 34 | /// Size of the hash result in bytes. 35 | /// 36 | public virtual int HashByteSize => 20; 37 | 38 | /// 39 | /// Size of the blocks used in each round. 40 | /// 41 | public virtual int BlockByteSize => 64; 42 | 43 | 44 | private SHA1 hash = SHA1.Create(); 45 | 46 | 47 | 48 | /// 49 | /// Computes the hash value for the specified byte array. 50 | /// 51 | /// 52 | /// 53 | /// The byte array to compute hash for 54 | /// The computed hash 55 | public byte[] ComputeHash(byte[] data) 56 | { 57 | if (disposedValue) 58 | throw new ObjectDisposedException("Instance was disposed."); 59 | if (data == null) 60 | throw new ArgumentNullException(nameof(data), "Data can not be null."); 61 | 62 | return IsDouble ? hash.ComputeHash(hash.ComputeHash(data)) : hash.ComputeHash(data); 63 | } 64 | 65 | 66 | /// 67 | /// Computes the hash value for the specified region of the specified byte array. 68 | /// 69 | /// 70 | /// 71 | /// 72 | /// The byte array to compute hash for 73 | /// The offset into the byte array from which to begin using data. 74 | /// The number of bytes in the array to use as data. 75 | /// The computed hash 76 | public byte[] ComputeHash(byte[] buffer, int offset, int count) 77 | { 78 | return ComputeHash(buffer.SubArray(offset, count)); 79 | } 80 | 81 | 82 | 83 | #region IDisposable Support 84 | private bool disposedValue = false; // To detect redundant calls 85 | 86 | protected virtual void Dispose(bool disposing) 87 | { 88 | if (!disposedValue) 89 | { 90 | if (disposing) 91 | { 92 | if (hash != null) 93 | hash.Dispose(); 94 | hash = null; 95 | } 96 | 97 | disposedValue = true; 98 | } 99 | } 100 | 101 | /// 102 | /// Releases all resources used by the current instance of the class. 103 | /// 104 | public void Dispose() 105 | { 106 | Dispose(true); 107 | } 108 | #endregion 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/Encoders/Base43.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using System; 7 | 8 | namespace BitcoinTransactionTool.Backend.Encoders 9 | { 10 | /// 11 | /// Base-43 is a special encoding based on encoding that Electrum uses to encode transactions 12 | /// before turning them into QR code. 13 | /// 14 | public class Base43 : Base58 15 | { 16 | /// 17 | /// Initializes a new instance of the using parameters of the given 18 | /// and using default Base-43 characters. 19 | /// 20 | public Base43() : base() 21 | { 22 | // https://github.com/spesmilo/electrum/blob/b39c51adf7ef9d56bd45b1c30a86d4d415ef7940/electrum/bitcoin.py#L428 23 | b58Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ$*+-./:"; 24 | 25 | baseValue = 43; 26 | logBaseValue = 679; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/IDeserializable.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Backend 7 | { 8 | public interface IDeserializable 9 | { 10 | /// 11 | /// Converts this instance into its byte array representation. 12 | /// 13 | /// An array of bytes 14 | byte[] Serialize(); 15 | 16 | /// 17 | /// Deserializes the given byte array starting from the specified offset. The return value indicates success. 18 | /// 19 | /// Byte array to use. 20 | /// The offset inside the to start from 21 | /// Error message (null if sucessful, otherwise will contain information about the failure) 22 | /// True if deserialization was successful, false if otherwise 23 | bool TryDeserialize(byte[] data, ref int offset, out string error); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/JsonConverterHelper.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts; 7 | using BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations; 8 | using BitcoinTransactionTool.Backend.Encoders; 9 | using Newtonsoft.Json; 10 | using System; 11 | using System.Linq; 12 | using System.Text; 13 | 14 | namespace BitcoinTransactionTool.Backend 15 | { 16 | internal class ByteArrayHexConverter : JsonConverter 17 | { 18 | public ByteArrayHexConverter(bool reverseHex) 19 | { 20 | reverse = reverseHex; 21 | } 22 | 23 | private readonly bool reverse; 24 | 25 | 26 | public override bool CanRead => true; 27 | public override bool CanWrite => true; 28 | 29 | public override bool CanConvert(Type objectType) => objectType == typeof(byte[]); 30 | 31 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 32 | { 33 | if (reader.TokenType == JsonToken.String) 34 | { 35 | string hex = serializer.Deserialize(reader); 36 | return Base16.ToByteArray(hex); 37 | } 38 | return serializer.Deserialize(reader); 39 | } 40 | 41 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 42 | { 43 | byte[] data = (byte[])value; 44 | string hexString = (data == null) ? string.Empty : reverse ? data.Reverse().ToArray().ToBase16() : data.ToBase16(); 45 | writer.WriteValue(hexString); 46 | } 47 | } 48 | 49 | 50 | 51 | internal class TransactionLocktimeConverter : JsonConverter 52 | { 53 | public override bool CanConvert(Type objectType) 54 | { 55 | return objectType == typeof(LockTime); 56 | } 57 | 58 | public override bool CanRead => false; 59 | public override bool CanWrite => true; 60 | 61 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 62 | { 63 | throw new NotImplementedException(); 64 | } 65 | 66 | 67 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 68 | { 69 | writer.WriteValue(((LockTime)value).ToString()); 70 | } 71 | } 72 | 73 | 74 | internal class TransactionScriptConverter : JsonConverter 75 | { 76 | public override bool CanConvert(Type objectType) 77 | { 78 | return objectType == typeof(SignatureScript) 79 | || objectType == typeof(PubkeyScript) 80 | || objectType == typeof(WitnessScript) 81 | || objectType == typeof(RedeemScript); 82 | } 83 | 84 | public override bool CanRead => false; 85 | public override bool CanWrite => true; 86 | 87 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 88 | { 89 | throw new NotImplementedException(); 90 | } 91 | 92 | 93 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 94 | { 95 | IScript scr = (IScript)value; 96 | 97 | writer.WriteValue(ScriptToString(scr.OperationList)); 98 | } 99 | 100 | private string ScriptToString(IOperation[] ops) 101 | { 102 | StringBuilder sb = new StringBuilder(ops.Length); 103 | foreach (var op in ops) 104 | { 105 | if (op is PushDataOp) 106 | { 107 | if (((PushDataOp)op).data == null) 108 | { 109 | string opName = op.OpValue.ToString(); 110 | if (opName.Contains('_')) 111 | { 112 | sb.Append($"OP{opName} "); 113 | } 114 | else 115 | { 116 | sb.Append($"OP_{opName} "); 117 | } 118 | } 119 | else 120 | { 121 | sb.Append($"PushData<{((PushDataOp)op).data.ToBase16()}> "); 122 | } 123 | } 124 | else if (op is ReturnOp) 125 | { 126 | sb.Append($"OP_{op.OpValue.ToString()}<{((ReturnOp)op).Data.ToBase16()}>"); 127 | } 128 | else if (op is IfElseOp) 129 | { 130 | string main = ScriptToString(((IfElseOp)op).mainOps); 131 | sb.Append($"OP_{op.OpValue.ToString()} {main} "); 132 | if (((IfElseOp)op).elseOps != null) 133 | { 134 | string branch = ScriptToString(((IfElseOp)op).elseOps); 135 | sb.Append($"OP_{OP.ELSE} {branch} "); 136 | } 137 | sb.Append($"OP_{OP.EndIf.ToString()} "); 138 | } 139 | else 140 | { 141 | sb.Append($"OP_{op.OpValue.ToString()} "); 142 | } 143 | } 144 | 145 | return sb.ToString().TrimEnd(' '); 146 | } 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/MVVM/BindableCommand.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using System; 7 | using System.Windows.Input; 8 | 9 | namespace BitcoinTransactionTool.Backend.MVVM 10 | { 11 | public class BindableCommand : ICommand 12 | { 13 | public BindableCommand(Action parameterizedAction) 14 | { 15 | ExecuteMethod = parameterizedAction; 16 | } 17 | public BindableCommand(Action parameterizedAction, Func canExecute) 18 | { 19 | ExecuteMethod = parameterizedAction; 20 | CanExecuteMethod = canExecute; 21 | } 22 | 23 | 24 | private readonly Action ExecuteMethod; 25 | private readonly Func CanExecuteMethod; 26 | 27 | 28 | public void RaiseCanExecuteChanged() 29 | { 30 | CanExecuteChanged(this, EventArgs.Empty); 31 | } 32 | 33 | 34 | public bool CanExecute(object parameter) 35 | { 36 | if (CanExecuteMethod != null) 37 | { 38 | return CanExecuteMethod(); 39 | } 40 | if (ExecuteMethod != null) 41 | { 42 | return true; 43 | } 44 | return false; 45 | } 46 | 47 | public event EventHandler CanExecuteChanged = delegate { }; 48 | 49 | public void Execute(object parameter) 50 | { 51 | ExecuteMethod?.Invoke(parameter); 52 | } 53 | } 54 | 55 | 56 | 57 | public class RelayCommand : ICommand 58 | { 59 | public RelayCommand(Action executeMethod) 60 | { 61 | ExecuteMethod = executeMethod; 62 | } 63 | public RelayCommand(Action executeMethod, Func canExecuteMethod) 64 | { 65 | ExecuteMethod = executeMethod; 66 | CanExecuteMethod = canExecuteMethod; 67 | } 68 | 69 | 70 | private readonly Action ExecuteMethod; 71 | private readonly Func CanExecuteMethod; 72 | 73 | 74 | public void RaiseCanExecuteChanged() 75 | { 76 | CanExecuteChanged(this, EventArgs.Empty); 77 | } 78 | 79 | 80 | public bool CanExecute(object parameter) 81 | { 82 | if (CanExecuteMethod != null) 83 | { 84 | return CanExecuteMethod(); 85 | } 86 | if (ExecuteMethod != null) 87 | { 88 | return true; 89 | } 90 | return false; 91 | } 92 | 93 | public event EventHandler CanExecuteChanged = delegate { }; 94 | 95 | public void Execute(object parameter) 96 | { 97 | ExecuteMethod?.Invoke(); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/MVVM/DependsOnPropertyAttribute.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using System; 7 | 8 | namespace BitcoinTransactionTool.Backend.MVVM 9 | { 10 | [AttributeUsage(AttributeTargets.Property)] 11 | public class DependsOnPropertyAttribute : Attribute 12 | { 13 | /// 14 | /// Initializes a new instance of using depending properties names. 15 | /// 16 | /// Names of the properties that the property with this attribute depends on. 17 | public DependsOnPropertyAttribute(params string[] dependingPropertyNames) 18 | { 19 | DependentProps = dependingPropertyNames; 20 | } 21 | 22 | /// 23 | /// Names of all the properties that the property with this attribute depends on. 24 | /// 25 | public readonly string[] DependentProps; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/MVVM/InpcBase.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using System.Collections.Generic; 7 | using System.ComponentModel; 8 | using System.Reflection; 9 | using System.Runtime.CompilerServices; 10 | 11 | namespace BitcoinTransactionTool.Backend.MVVM 12 | { 13 | /// 14 | /// Base (abstract) class implementing . 15 | /// Could be used for both ViewModels and Models 16 | /// 17 | public abstract class InpcBase : INotifyPropertyChanged 18 | { 19 | public InpcBase() 20 | { 21 | PropertyDependencyMap = new Dictionary>(); 22 | 23 | foreach (PropertyInfo property in GetType().GetProperties()) 24 | { 25 | foreach (DependsOnPropertyAttribute dependsAttr in property.GetCustomAttributes()) 26 | { 27 | if (dependsAttr == null) 28 | { 29 | continue; 30 | } 31 | 32 | foreach (string dependence in dependsAttr.DependentProps) 33 | { 34 | if (!PropertyDependencyMap.ContainsKey(dependence)) 35 | { 36 | PropertyDependencyMap.Add(dependence, new List()); 37 | } 38 | PropertyDependencyMap[dependence].Add(property.Name); 39 | } 40 | } 41 | } 42 | } 43 | 44 | 45 | /// 46 | /// Dictonary of all properties which have a dependant property. 47 | /// 48 | protected Dictionary> PropertyDependencyMap; 49 | 50 | /// 51 | /// The PropertyChanged Event to raise to any UI object 52 | /// 53 | public event PropertyChangedEventHandler PropertyChanged; 54 | 55 | /// 56 | /// The PropertyChanged Event to raise to any UI object 57 | /// The event is only invoked if data binding is used 58 | /// 59 | /// The Name of the property that is changing. 60 | protected void RaisePropertyChanged(string propertyName) 61 | { 62 | PropertyChangedEventHandler handler = PropertyChanged; 63 | if (handler != null) 64 | { 65 | // Raise the PropertyChanged event. 66 | handler(this, new PropertyChangedEventArgs(propertyName)); 67 | 68 | // Raise the PropertyChanged event for dependant properties too. 69 | if (PropertyDependencyMap.ContainsKey(propertyName)) 70 | { 71 | foreach (string p in PropertyDependencyMap[propertyName]) 72 | { 73 | handler(this, new PropertyChangedEventArgs(p)); 74 | } 75 | } 76 | } 77 | } 78 | 79 | /// 80 | /// Sets the value of a property. 81 | /// 82 | /// 83 | /// 84 | /// 85 | /// The Name of the property that is changing. If null it passes caller name in compile time. 86 | /// Returs false if value didn't change. 87 | protected bool SetField(ref T field, T value, [CallerMemberName] string propertyName = null) 88 | { 89 | if (EqualityComparer.Default.Equals(field, value)) 90 | { 91 | return false; 92 | } 93 | else 94 | { 95 | field = value; 96 | RaisePropertyChanged(propertyName); 97 | return true; 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/MVVM/ValidatableBase.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using System; 7 | using System.Collections; 8 | using System.Collections.Generic; 9 | using System.ComponentModel; 10 | 11 | namespace BitcoinTransactionTool.Backend.MVVM 12 | { 13 | /// 14 | /// Base (abstract) class implementing and inherits from . 15 | /// Could be used for any model that requires validation. 16 | /// 17 | public abstract class ValidatableBase : InpcBase, INotifyDataErrorInfo 18 | { 19 | /// 20 | /// List of all errors with property name as its key. 21 | /// 22 | private readonly Dictionary> errorList = new Dictionary>(); 23 | 24 | 25 | /// 26 | /// When overriden should implement validation logic specific to the model. 27 | /// Call method at the start of validation to clear all errors of that property. 28 | /// 29 | public abstract void Validate(); 30 | 31 | 32 | public void AddError(string propertyName, string error) 33 | { 34 | if (!errorList.ContainsKey(propertyName)) 35 | { 36 | errorList[propertyName] = new List(); 37 | } 38 | if (!errorList[propertyName].Contains(error)) 39 | { 40 | errorList[propertyName].Add(error); 41 | RaiseErrorsChanged(propertyName); 42 | } 43 | } 44 | 45 | public void ClearErrors(string propertyName) 46 | { 47 | if (errorList.ContainsKey(propertyName)) 48 | { 49 | errorList.Remove(propertyName); 50 | RaiseErrorsChanged(propertyName); 51 | } 52 | } 53 | 54 | public void RaiseErrorsChanged(string propertyName) 55 | { 56 | ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName)); 57 | } 58 | 59 | 60 | 61 | public bool HasErrors => errorList.Count > 0; 62 | 63 | public event EventHandler ErrorsChanged; 64 | 65 | public IEnumerable GetErrors(string propertyName) 66 | { 67 | if (!string.IsNullOrEmpty(propertyName)) 68 | { 69 | errorList.TryGetValue(propertyName, out List res); 70 | return res; 71 | } 72 | else 73 | { 74 | return null; 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Backend/MVVM/ViewModelBase.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Backend.MVVM 7 | { 8 | public abstract class ViewModelBase : InpcBase 9 | { 10 | /// 11 | /// Used for changing the visibility of error message TextBox. 12 | /// 13 | [DependsOnProperty(nameof(Errors))] 14 | public bool IsErrorMsgVisible => !string.IsNullOrEmpty(Errors); 15 | 16 | /// 17 | /// String containing all the errors. 18 | /// 19 | public string Errors 20 | { 21 | get => _errors; 22 | set => SetField(ref _errors, value); 23 | } 24 | private string _errors; 25 | 26 | /// 27 | /// Status, showing current action being performed. 28 | /// 29 | public string Status 30 | { 31 | get { return _status; } 32 | set { SetField(ref _status, value); } 33 | } 34 | private string _status; 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Bitcoin Icon.png.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coding-Enthusiast/BitcoinTransactionTool/0f25a89eb2408fc4e96b6985aca34dee6894da0c/BitcoinTransactionTool/Bitcoin Icon.png.ico -------------------------------------------------------------------------------- /BitcoinTransactionTool/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Models; 7 | using BitcoinTransactionTool.ViewModels; 8 | using System.Collections; 9 | using System.Collections.ObjectModel; 10 | using System.Linq; 11 | using System.Windows; 12 | using System.Windows.Controls; 13 | 14 | namespace BitcoinTransactionTool 15 | { 16 | /// 17 | /// Interaction logic for MainWindow.xaml 18 | /// 19 | public partial class MainWindow : Window 20 | { 21 | public MainWindow() 22 | { 23 | InitializeComponent(); 24 | } 25 | 26 | private void Exit_Click(object sender, RoutedEventArgs e) 27 | { 28 | this.Close(); 29 | } 30 | 31 | private void ListView_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) 32 | { 33 | ListView lv = sender as ListView; 34 | IList selected = lv.SelectedItems; 35 | 36 | ((MainWindowViewModel)DataContext).SelectedUTXOs = 37 | new ObservableCollection(selected.Cast()); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Models/BitcoinAddress.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend; 7 | using BitcoinTransactionTool.Backend.Encoders; 8 | using BitcoinTransactionTool.Backend.MVVM; 9 | 10 | namespace BitcoinTransactionTool.Models 11 | { 12 | public class BitcoinAddress : ValidatableBase 13 | { 14 | private string _addr; 15 | public string Address 16 | { 17 | get { return _addr; } 18 | set 19 | { 20 | if (SetField(ref _addr, value)) 21 | { 22 | Validate(); 23 | } 24 | } 25 | } 26 | 27 | 28 | public override void Validate() 29 | { 30 | ClearErrors(nameof(Address)); 31 | 32 | if (string.IsNullOrEmpty(Address)) 33 | { 34 | AddError(nameof(Address), "Address can not be empty."); 35 | } 36 | else if (Address.StartsWith("1") || Address.StartsWith("3")) 37 | { 38 | if (!new Base58().IsValid(Address)) 39 | { 40 | AddError(nameof(Address), "Invalid Base58 encoded address."); 41 | } 42 | } 43 | else if (Address.StartsWith("bc1")) 44 | { 45 | if (!new Bech32().IsValid(Address)) 46 | { 47 | AddError(nameof(Address), "Invalid Bech32 encoded address."); 48 | } 49 | } 50 | else 51 | { 52 | AddError(nameof(Address), "Invalid address format."); 53 | } 54 | } 55 | } 56 | 57 | 58 | public class SendingAddress : BitcoinAddress 59 | { 60 | private ulong _satBal; 61 | public ulong BalanceSatoshi 62 | { 63 | get { return _satBal; } 64 | set { SetField(ref _satBal, value); } 65 | } 66 | 67 | /// 68 | /// Balance is the user friendly way of showing the balance in decimal format. 69 | /// 70 | [DependsOnProperty(nameof(BalanceSatoshi))] 71 | public decimal Balance 72 | { 73 | get { return BalanceSatoshi * Constants.Satoshi; } 74 | } 75 | } 76 | 77 | 78 | public class ReceivingAddress : BitcoinAddress 79 | { 80 | public ReceivingAddress() { } 81 | 82 | public ReceivingAddress(string addr, decimal amount) 83 | { 84 | Address = addr; 85 | Payment = amount; 86 | } 87 | 88 | public ReceivingAddress(string addr, ulong amount) 89 | { 90 | Address = addr; 91 | Payment = amount * Constants.Satoshi; 92 | } 93 | 94 | /// 95 | /// PaymentSatoshi is the real payment value which is used in the code. 96 | /// 97 | [DependsOnProperty(nameof(Payment))] 98 | public ulong PaymentSatoshi 99 | { 100 | get { return (ulong)(Payment * (1 / Constants.Satoshi)); } 101 | } 102 | 103 | /// 104 | /// Payment is the user friendly way of showing amount to pay in decimal format. 105 | /// 106 | public decimal Payment 107 | { 108 | get { return _payment; } 109 | set { SetField(ref _payment, value); } 110 | } 111 | private decimal _payment; 112 | 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Models/ButtonModel.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts; 7 | using BitcoinTransactionTool.Backend.MVVM; 8 | using System; 9 | using System.ComponentModel; 10 | 11 | namespace BitcoinTransactionTool.Models 12 | { 13 | public class ButtonModel 14 | { 15 | public ButtonModel(OP op, bool enabled, Action methodToRun) 16 | { 17 | Name = $"OP__{op.ToString()}"; 18 | OpCode = op; 19 | 20 | DescriptionAttribute[] desc = GetDescriptions(op); 21 | Description = (desc == null || desc.Length == 0) ? Name : desc[0].Description; 22 | 23 | RunCommand = new BindableCommand(methodToRun); 24 | Enabled = enabled; 25 | } 26 | 27 | private DescriptionAttribute[] GetDescriptions(OP op) 28 | { 29 | return op.GetType() 30 | .GetField(op.ToString()) 31 | .GetCustomAttributes(typeof(DescriptionAttribute), false) 32 | as DescriptionAttribute[]; 33 | } 34 | 35 | public string Name { get; set; } 36 | public string Description { get; set; } 37 | public bool Enabled { get; set; } 38 | public OP OpCode { get; set; } 39 | public BindableCommand RunCommand { get; set; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Models/PublicKeyModel.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend.Encoders; 7 | using BitcoinTransactionTool.Backend.MVVM; 8 | using System; 9 | 10 | namespace BitcoinTransactionTool.Models 11 | { 12 | public class PublicKeyModel : ValidatableBase 13 | { 14 | private string _key; 15 | public string PubKey 16 | { 17 | get => _key; 18 | set 19 | { 20 | if (SetField(ref _key, value)) 21 | { 22 | Validate(); 23 | } 24 | } 25 | } 26 | 27 | 28 | public override void Validate() 29 | { 30 | ClearErrors(nameof(PubKey)); 31 | 32 | // TODO: replace this with Autarkysoft.Cryptocurrency.Keypairs.PublicKey for real validations! 33 | 34 | if (string.IsNullOrEmpty(PubKey)) 35 | { 36 | AddError(nameof(PubKey), "PubKey can not be empty."); 37 | } 38 | else if (!Base16.IsValid(PubKey)) 39 | { 40 | AddError(nameof(PubKey), "PubKey input is not a base-16 encoded string."); 41 | } 42 | else 43 | { 44 | byte[] ba = Base16.ToByteArray(PubKey); 45 | if (ba.Length != 33 && ba.Length != 65) 46 | { 47 | AddError(nameof(PubKey), "PubKey input has invalid length."); 48 | } 49 | else if (ba.Length == 33 && ba[0] != 0x02 && ba[0] != 0x03) 50 | { 51 | AddError(nameof(PubKey), "Compressed PubKey needs to start with 0x02 or 0x03."); 52 | } 53 | else if (ba.Length == 65 && ba[0] != 0x04) 54 | { 55 | AddError(nameof(PubKey), "Uncompressed PubKey needs to start with 0x04."); 56 | } 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Models/UTXO.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | namespace BitcoinTransactionTool.Models 7 | { 8 | public class UTXO 9 | { 10 | public UTXO() { } 11 | 12 | public UTXO(string txid, uint index) 13 | { 14 | TxHash = txid; 15 | OutIndex = index; 16 | } 17 | 18 | 19 | public string Address { get; set; } 20 | public string AddressHash160 { get; set; } 21 | public string TxHash { get; set; } 22 | public uint OutIndex { get; set; } 23 | public int Confirmation { get; set; } 24 | 25 | /// 26 | /// Amount of bitcoin in current UTXO in satoshi 27 | /// 28 | public ulong Amount { get; set; } 29 | 30 | /// 31 | /// Bitcoin amount in bitcoin (*10e-8) for user interface only 32 | /// 33 | public decimal AmountBitcoin 34 | { 35 | get 36 | { 37 | return Amount * 0.00000001m; 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("BitcoinTransactionTool")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("Coding Enthusiast")] 14 | [assembly: AssemblyProduct("BitcoinTransactionTool")] 15 | [assembly: AssemblyCopyright("Copyright © Coding Enthusiast 2017")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | //In order to begin building localizable applications, set 25 | //CultureYouAreCodingWith in your .csproj file 26 | //inside a . For example, if you are using US english 27 | //in your source files, set the to en-US. Then uncomment 28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 29 | //the line below to match the UICulture setting in the project file. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 36 | //(used if a resource is not found in the page, 37 | // or application resource dictionaries) 38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 39 | //(used if a resource is not found in the page, 40 | // app, or any theme specific resource dictionaries) 41 | )] 42 | 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("0.11.0.0")] 55 | [assembly: AssemblyFileVersion("0.11.0.0")] 56 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace BitcoinTransactionTool.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("BitcoinTransactionTool.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace BitcoinTransactionTool.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.3.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Services/Api.cs: -------------------------------------------------------------------------------- 1 | using BitcoinTransactionTool.Models; 2 | using Newtonsoft.Json.Linq; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Net.Http; 6 | using System.Threading.Tasks; 7 | 8 | namespace BitcoinTransactionTool.Services 9 | { 10 | public enum TxApiNames 11 | { 12 | BlockCypher, 13 | BlockchainInfo, 14 | } 15 | 16 | public abstract class Api 17 | { 18 | protected async Task> SendApiRequestAsync(string url) 19 | { 20 | Response resp = new Response(); 21 | using (HttpClient client = new HttpClient()) 22 | { 23 | try 24 | { 25 | string result = await client.GetStringAsync(url); 26 | if (result.StartsWith("[")) 27 | { 28 | resp.Result = new JObject 29 | { 30 | { "Result", JArray.Parse(result) } 31 | }; 32 | } 33 | else 34 | { 35 | resp.Result = JObject.Parse(result); 36 | } 37 | } 38 | catch (Exception ex) 39 | { 40 | string errMsg = (ex.InnerException == null) ? 41 | ex.Message : 42 | ex.Message + Environment.NewLine + ex.InnerException.Message; 43 | resp.Errors.Add(errMsg); 44 | } 45 | } 46 | return resp; 47 | } 48 | } 49 | 50 | public abstract class TransactionApi : Api 51 | { 52 | public abstract Task>> GetUTXO(List addrList); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Services/ErrorCollection.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace BitcoinTransactionTool.Services 6 | { 7 | public class ErrorCollection : IReadOnlyCollection 8 | { 9 | private readonly List ErrorList = new List(); 10 | 11 | 12 | /// 13 | /// Returns true if there is any errors available. 14 | /// 15 | /// true if there is any error, false if empty. 16 | public bool Any() 17 | { 18 | return ErrorList.Count > 0; 19 | } 20 | 21 | /// 22 | /// Adds one error to the list of errors 23 | /// 24 | /// Error string to add. 25 | internal void Add(string errorMessage) 26 | { 27 | ErrorList.Add(errorMessage); 28 | } 29 | 30 | /// 31 | /// Adds multiple errors to the list of errors 32 | /// 33 | /// List of errors to add. 34 | internal void AddRange(IEnumerable multiError) 35 | { 36 | ErrorList.AddRange(multiError); 37 | } 38 | 39 | /// 40 | /// Clears all errors 41 | /// 42 | internal void Clear() 43 | { 44 | ErrorList.Clear(); 45 | } 46 | 47 | /// 48 | /// Returns a formated string of all the errors. 49 | /// 50 | /// Formatted string of all the errors 51 | public string GetErrors() 52 | { 53 | StringBuilder sb = new StringBuilder(); 54 | foreach (var item in ErrorList) 55 | { 56 | sb.AppendLine("- " + item); 57 | } 58 | return sb.ToString(); 59 | } 60 | 61 | 62 | #region IReadOnlyCollection 63 | 64 | public int Count 65 | { 66 | get { return ErrorList.Count; } 67 | } 68 | 69 | public IEnumerator GetEnumerator() 70 | { 71 | return ErrorList.GetEnumerator(); 72 | } 73 | 74 | IEnumerator IEnumerable.GetEnumerator() 75 | { 76 | return ((IEnumerable)ErrorList).GetEnumerator(); 77 | } 78 | 79 | #endregion 80 | 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Services/OperationConverter.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts; 7 | using BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations; 8 | using System; 9 | 10 | namespace BitcoinTransactionTool.Services 11 | { 12 | public class OperationConverter 13 | { 14 | // A Fake reader used only for the coversion of OP to IOperation 15 | private class ScriptReader : Script 16 | { 17 | public ScriptReader() 18 | { 19 | IsWitness = false; 20 | } 21 | } 22 | 23 | // two Fake ops only used for returning an IOperation, not to be used for anything else. 24 | private class ElseOp : IOperation 25 | { 26 | public OP OpValue => OP.ELSE; 27 | public bool Run(IOpData opData, out string error) => throw new NotImplementedException(); 28 | } 29 | private class EndIfOp : IOperation 30 | { 31 | public OP OpValue => OP.EndIf; 32 | public bool Run(IOpData opData, out string error) => throw new NotImplementedException(); 33 | } 34 | 35 | private readonly ScriptReader reader = new ScriptReader(); 36 | 37 | public IOperation ConvertToOperation(OP op) 38 | { 39 | switch (op) 40 | { 41 | case OP.IF: 42 | return new IFOp(); 43 | case OP.NotIf: 44 | return new NotIfOp(); 45 | case OP.ELSE: 46 | return new ElseOp(); 47 | case OP.EndIf: 48 | return new EndIfOp(); 49 | } 50 | 51 | byte[] data = new byte[2] { 1, (byte)op }; 52 | int offset = 0; 53 | if (reader.TryDeserialize(data, ref offset, out string error)) 54 | { 55 | return reader.OperationList[0]; 56 | } 57 | else 58 | { 59 | throw new ArgumentException($"An error occured while trying to convert: {error}"); 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Services/PushServices.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | using System.Threading.Tasks; 3 | 4 | namespace BitcoinTransactionTool.Services 5 | { 6 | public interface IPushService 7 | { 8 | Task PushTx(string txToPush); 9 | } 10 | //public class BlockexplorerApi : IPushService 11 | //{ 12 | // public async Task PushTx(string txToPush) 13 | // { 14 | // using (HttpClient client = new HttpClient()) 15 | // { 16 | // string url = "https://blockexplorer.com/api/tx/send"; 17 | // HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Post, url); 18 | // req.Headers.Add("rawtx", txToPush); 19 | // var result = await client.SendAsync(req); 20 | // return await result.Content.ReadAsStringAsync(); 21 | // } 22 | // } 23 | //} 24 | } 25 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Services/Response.cs: -------------------------------------------------------------------------------- 1 | namespace BitcoinTransactionTool.Services 2 | { 3 | public class Response : Response 4 | { 5 | public T Result { get; set; } 6 | } 7 | 8 | 9 | public class Response 10 | { 11 | public ErrorCollection Errors { get; } = new ErrorCollection(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Services/ScriptReader.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend; 7 | using BitcoinTransactionTool.Backend.Blockchain.Scripts; 8 | using BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations; 9 | using BitcoinTransactionTool.Backend.Encoders; 10 | 11 | namespace BitcoinTransactionTool.Services 12 | { 13 | public class ScriptReader 14 | { 15 | private class Helper : Script 16 | { 17 | public Helper() 18 | { 19 | IsWitness = false; 20 | } 21 | } 22 | 23 | public Response Read(string hex) 24 | { 25 | Response resp = new Response(); 26 | 27 | if (!Base16.IsValid(hex)) 28 | { 29 | resp.Errors.Add("Invalid base-16 string."); 30 | } 31 | else 32 | { 33 | byte[] data = Base16.ToByteArray(hex); 34 | int offset = 0; 35 | CompactInt len = new CompactInt(data.Length); 36 | data = len.ToByteArray().ConcatFast(data); 37 | 38 | Script scr = new Helper(); 39 | if (scr.TryDeserialize(data, ref offset, out string error)) 40 | { 41 | resp.Result = scr.OperationList; 42 | } 43 | else 44 | { 45 | resp.Errors.Add(error); 46 | } 47 | } 48 | 49 | return resp; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Services/ScriptToStringConverter.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend; 7 | using BitcoinTransactionTool.Backend.Blockchain.Scripts; 8 | using BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations; 9 | using System.Collections.Generic; 10 | using System.Text; 11 | 12 | namespace BitcoinTransactionTool.Services 13 | { 14 | public class ScriptToStringConverter 15 | { 16 | private readonly StringBuilder sb = new StringBuilder(); 17 | 18 | private string OpValueToString(OP op) 19 | { 20 | return $"OP_{op.ToString().Replace("_", string.Empty)} "; 21 | } 22 | 23 | private void Convert(IOperation op) 24 | { 25 | if (op is PushDataOp push) 26 | { 27 | // for OP_numbers data is null for the rest ToByteArray() contains the length 28 | if (push.data is null) 29 | { 30 | sb.Append(OpValueToString(op.OpValue)); 31 | } 32 | else 33 | { 34 | sb.Append($"<{((PushDataOp)op).data.ToBase16()}> "); 35 | } 36 | } 37 | else if (op is ReturnOp ret) 38 | { 39 | if (ret.Data.Length == 1) 40 | { 41 | sb.Append(OpValueToString(op.OpValue)); 42 | } 43 | else 44 | { 45 | sb.Append($"{OpValueToString(op.OpValue).TrimEnd(' ')}<{ret.Data.ToBase16()}> "); 46 | } 47 | } 48 | else if (op is IfElseOp conditional) 49 | { 50 | sb.Append(OpValueToString(op.OpValue)); 51 | if (conditional.mainOps is null) 52 | { 53 | return; // This happens when the buttons are used to create an OP_IF 54 | } 55 | foreach (var main in conditional.mainOps) 56 | { 57 | Convert(main); 58 | } 59 | if (!(conditional.elseOps is null)) 60 | { 61 | sb.Append(OpValueToString(OP.ELSE)); 62 | foreach (var branch in conditional.elseOps) 63 | { 64 | Convert(branch); 65 | } 66 | } 67 | sb.Append(OpValueToString(OP.EndIf)); 68 | } 69 | else 70 | { 71 | sb.Append(OpValueToString(op.OpValue)); 72 | } 73 | } 74 | 75 | public string GetString(IEnumerable opList) 76 | { 77 | sb.Clear(); 78 | 79 | foreach (var op in opList) 80 | { 81 | Convert(op); 82 | } 83 | 84 | return sb.ToString(); 85 | } 86 | 87 | public string GetHex(IEnumerable opList) 88 | { 89 | sb.Clear(); 90 | 91 | foreach (var op in opList) 92 | { 93 | if (op is PushDataOp push) 94 | { 95 | sb.Append(push.ToByteArray().ToBase16()); 96 | } 97 | else if (op is ReturnOp ret) 98 | { 99 | sb.Append(ret.ToByteArray().ToBase16()); 100 | } 101 | else if (op is IfElseOp conditional) 102 | { 103 | if (conditional.mainOps is null) 104 | { 105 | sb.Append($"{(byte)op.OpValue:x2}"); 106 | } 107 | else 108 | { 109 | sb.Append(conditional.ToByteArray().ToBase16()); 110 | } 111 | } 112 | else 113 | { 114 | sb.Append($"{(byte)op.OpValue:x2}"); 115 | } 116 | } 117 | 118 | return sb.ToString(); 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Services/TransactionServices/BlockCypher.cs: -------------------------------------------------------------------------------- 1 | using BitcoinTransactionTool.Models; 2 | using Newtonsoft.Json.Linq; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace BitcoinTransactionTool.Services.TransactionServices 8 | { 9 | public class BlockCypher : TransactionApi 10 | { 11 | public override async Task>> GetUTXO(List addrList) 12 | { 13 | Response> resp = new Response>(); 14 | string addresses = string.Join(";", addrList.Select(b => b.Address).ToArray()); 15 | string url = $"https://api.blockcypher.com/v1/btc/main/addrs/{addresses}?unspentOnly=true"; 16 | Response apiResp = await SendApiRequestAsync(url); 17 | if (apiResp.Errors.Any()) 18 | { 19 | resp.Errors.AddRange(apiResp.Errors); 20 | return resp; 21 | } 22 | 23 | resp.Result = new List(); 24 | if (apiResp.Result["Result"] != null) 25 | { 26 | foreach (var item in apiResp.Result["Result"]) 27 | { 28 | if ((int)item["final_n_tx"] != 0) 29 | { 30 | foreach (var tx in item["txrefs"]) 31 | { 32 | UTXO u = new UTXO() 33 | { 34 | Address = item["address"].ToString(), 35 | AddressHash160 = "", 36 | TxHash = tx["tx_hash"].ToString(), 37 | Amount = (ulong)tx["value"], 38 | Confirmation = (int)tx["confirmations"], 39 | OutIndex = (uint)tx["tx_output_n"] 40 | }; 41 | resp.Result.Add(u); 42 | } 43 | } 44 | } 45 | } 46 | else if ((int)apiResp.Result["final_n_tx"] != 0) 47 | { 48 | foreach (var tx in apiResp.Result["txrefs"]) 49 | { 50 | UTXO u = new UTXO() 51 | { 52 | Address = apiResp.Result["address"].ToString(), 53 | AddressHash160 = "", 54 | TxHash = tx["tx_hash"].ToString(), 55 | Amount = (ulong)tx["value"], 56 | Confirmation = (int)tx["confirmations"], 57 | OutIndex = (uint)tx["tx_output_n"] 58 | }; 59 | resp.Result.Add(u); 60 | } 61 | } 62 | 63 | return resp; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Services/TransactionServices/BlockchainInfo.cs: -------------------------------------------------------------------------------- 1 | using BitcoinTransactionTool.Models; 2 | using CommonLibrary; 3 | using Newtonsoft.Json.Linq; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace BitcoinTransactionTool.Services.TransactionServices 9 | { 10 | public class BlockchainInfo : TransactionApi 11 | { 12 | public override async Task>> GetUTXO(List addrList) 13 | { 14 | Response> resp = new Response>(); 15 | string addresses = string.Join("|", addrList.Select(b => b.Address).ToArray()); 16 | string url = "https://blockchain.info/unspent?active=" + addresses; 17 | Response apiResp = await SendApiRequestAsync(url); 18 | if (apiResp.Errors.Any()) 19 | { 20 | resp.Errors.AddRange(apiResp.Errors); 21 | return resp; 22 | } 23 | 24 | resp.Result = new List(); 25 | foreach (var item in apiResp.Result["unspent_outputs"]) 26 | { 27 | UTXO u = new UTXO(); 28 | string script = item["script"].ToString(); 29 | u.AddressHash160 = script.Substring("76a914".Length, script.Length - "76a91488ac".Length); 30 | u.Address = BitcoinConversions.Hash160ToBase58(u.AddressHash160); 31 | u.TxHash = item["tx_hash_big_endian"].ToString(); 32 | u.Amount = (ulong)item["value"]; 33 | u.Confirmation = (int)item["confirmations"]; 34 | u.OutIndex = (uint)item["tx_output_n"]; 35 | resp.Result.Add(u); 36 | } 37 | 38 | return resp; 39 | } 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Services/TxBuilder.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend; 7 | using BitcoinTransactionTool.Backend.Blockchain; 8 | using BitcoinTransactionTool.Backend.Blockchain.Scripts; 9 | using BitcoinTransactionTool.Backend.Encoders; 10 | using BitcoinTransactionTool.Models; 11 | using System; 12 | using System.Collections.Generic; 13 | using System.Linq; 14 | 15 | namespace BitcoinTransactionTool.Services 16 | { 17 | public enum WalletType 18 | { 19 | Normal, 20 | Core, 21 | Electrum 22 | } 23 | public class TxBuilder 24 | { 25 | private IPubkeyScript BuildPubkeyScript(string address) 26 | { 27 | Address addr = new Address(); 28 | if (!addr.TryGetType(address, out PubkeyScriptType scrType, out byte[] hash)) 29 | { 30 | throw new FormatException(); 31 | } 32 | 33 | PubkeyScript scr = new PubkeyScript(); 34 | switch (scrType) 35 | { 36 | case PubkeyScriptType.P2PKH: 37 | scr.SetToP2PKH(hash); 38 | break; 39 | case PubkeyScriptType.P2SH: 40 | scr.SetToP2SH(hash); 41 | break; 42 | case PubkeyScriptType.P2WPKH: 43 | scr.SetToP2WPKH(hash); 44 | break; 45 | case PubkeyScriptType.P2WSH: 46 | scr.SetToP2WSH(hash); 47 | break; 48 | default: 49 | throw new NotImplementedException(); 50 | } 51 | 52 | return scr; 53 | } 54 | 55 | public ITransaction Build(uint ver, List txToSpend, List receiveAddr, uint lockTime) 56 | { 57 | TxIn[] tIns = txToSpend.Select(x => new TxIn() 58 | { 59 | Outpoint = new Outpoint() { Index = x.OutIndex, TxHash = Base16.ToByteArray(Base16.Reverse(x.TxHash)) }, 60 | SigScript = new SignatureScript(), 61 | Sequence = uint.MaxValue 62 | }).ToArray(); 63 | 64 | TxOut[] tOuts = receiveAddr.Select(x => new TxOut() 65 | { 66 | Amount = x.PaymentSatoshi, 67 | PubScript = BuildPubkeyScript(x.Address) 68 | }).ToArray(); 69 | 70 | Transaction tx = new Transaction((int)ver, tIns, tOuts, lockTime); 71 | return tx; 72 | } 73 | 74 | 75 | /// 76 | /// Returns estimated size of the final signed transaction. 77 | /// 78 | /// Transactions to spend. 79 | /// New outputs to create. 80 | /// 81 | public int GetEstimatedTransactionSize(UTXO[] inputs, ReceivingAddress[] outputs) 82 | { 83 | if (inputs?.Length == 0 || outputs?.Length == 0) 84 | { 85 | return 0; 86 | } 87 | 88 | 89 | int c1 = new CompactInt(inputs.Length).ToByteArray().Length; 90 | int c2 = new CompactInt(outputs.Length).ToByteArray().Length; 91 | 92 | int outpointSize = new Outpoint().Size; 93 | 94 | int inputSize = 0; 95 | foreach (var item in inputs) 96 | { 97 | if (item.Address.StartsWith("1")) 98 | { 99 | inputSize += 100 | outpointSize 101 | + 1 //scriptSig length 102 | + 107 //scriptSig sig 103 | + 4; //sequence 104 | } 105 | else if (item.Address.StartsWith("3")) 106 | { 107 | inputSize += 108 | outpointSize 109 | + 1 //scriptSig length 110 | + 351 //scriptSig sig 111 | + 4; //sequence 112 | } 113 | else if (item.Address.StartsWith("bc")) 114 | { 115 | inputSize += 116 | outpointSize 117 | + 1 //scriptSig length 118 | + 61 //scriptSig sig 119 | + 4; //sequence 120 | } 121 | } 122 | 123 | int outputSize = 0; 124 | foreach (var item in outputs) 125 | { 126 | if (string.IsNullOrEmpty(item.Address)) 127 | { 128 | return 0; 129 | } 130 | 131 | if (item.Address.StartsWith("1")) 132 | { 133 | outputSize = 134 | 8 //Amount 135 | + 1 //pk_script length 136 | + 25; //pk_script 137 | } 138 | else if (item.Address.StartsWith("3")) 139 | { 140 | outputSize = 141 | 8 //Amount 142 | + 1 //pk_script length 143 | + 23; //pk_script 144 | } 145 | else if (item.Address.StartsWith("bc")) 146 | { 147 | outputSize = 148 | 8 //Amount 149 | + 1 //pk_script length 150 | + 25; //pk_script 151 | } 152 | } 153 | 154 | int totalSize = 155 | 4 //Version 156 | + c1 //TxIn Count 157 | + inputSize 158 | + c2 //TxOut Count 159 | + outputSize 160 | + 4; //LockTime 161 | 162 | return (totalSize <= 10) ? 0 : totalSize; 163 | } 164 | 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Services/WindowManager.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend.MVVM; 7 | using System.Windows; 8 | 9 | namespace BitcoinTransactionTool.Services 10 | { 11 | public interface IWindowManager 12 | { 13 | void Show(InpcBase ViewModel, string viewTitle); 14 | } 15 | 16 | 17 | public class WindowManager : IWindowManager 18 | { 19 | public void Show(InpcBase ViewModel, string viewTitle) 20 | { 21 | Window win = new Window() 22 | { 23 | Content = ViewModel, 24 | Owner = Application.Current.MainWindow, 25 | ResizeMode = ResizeMode.NoResize, 26 | WindowStartupLocation = WindowStartupLocation.CenterOwner, 27 | ShowInTaskbar = false, 28 | SizeToContent = SizeToContent.WidthAndHeight, 29 | Title = viewTitle 30 | }; 31 | 32 | win.ShowDialog(); 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/ViewModels/QrViewModel.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend; 7 | using BitcoinTransactionTool.Backend.Encoders; 8 | using BitcoinTransactionTool.Backend.MVVM; 9 | using QRCoder; 10 | using System; 11 | using System.Collections.Generic; 12 | using System.Drawing; 13 | using System.IO; 14 | using System.Linq; 15 | using System.Text; 16 | using System.Windows.Media.Imaging; 17 | 18 | namespace BitcoinTransactionTool.ViewModels 19 | { 20 | public class QrViewModel : ViewModelBase 21 | { 22 | public QrViewModel() 23 | { 24 | EncodingList = Enum.GetValues(typeof(Encoders)).Cast(); 25 | ShowCommand = new RelayCommand(ShowQr, () => !string.IsNullOrEmpty(RawTx)); 26 | } 27 | 28 | 29 | 30 | public enum Encoders 31 | { 32 | UTF8, 33 | Base16, 34 | Base58, 35 | Base58Check, 36 | Base43, 37 | Base64 38 | } 39 | 40 | private readonly Base58 b58enc = new Base58(); 41 | private readonly Base43 b43enc = new Base43(); 42 | 43 | 44 | 45 | public IEnumerable EncodingList { get; private set; } 46 | 47 | 48 | private Encoders _encIn; 49 | public Encoders SelectedInEncoder 50 | { 51 | get => _encIn; 52 | set => SetField(ref _encIn, value); 53 | } 54 | 55 | 56 | private Encoders _encOut; 57 | public Encoders SelectedOutEncoder 58 | { 59 | get => _encOut; 60 | set => SetField(ref _encOut, value); 61 | } 62 | 63 | 64 | private string _tx; 65 | public string RawTx 66 | { 67 | get => _tx; 68 | set 69 | { 70 | if (SetField(ref _tx, value)) 71 | { 72 | ShowCommand.RaiseCanExecuteChanged(); 73 | } 74 | } 75 | } 76 | 77 | 78 | private BitmapImage _qr; 79 | public BitmapImage QRCode 80 | { 81 | get => _qr; 82 | private set => SetField(ref _qr, value); 83 | } 84 | 85 | 86 | public RelayCommand ShowCommand { get; private set; } 87 | private void ShowQr() 88 | { 89 | try 90 | { 91 | Errors = string.Empty; 92 | 93 | byte[] input = GetInput(); 94 | string converted = (SelectedInEncoder == SelectedOutEncoder) ? RawTx : GetOutput(input); 95 | 96 | 97 | QRCodeGenerator qrGenerator = new QRCodeGenerator(); 98 | QRCodeData qrCodeData = qrGenerator.CreateQrCode(converted, QRCodeGenerator.ECCLevel.Q); 99 | QRCode qrCode = new QRCode(qrCodeData); 100 | Bitmap qrCodeImage = qrCode.GetGraphic(20); 101 | 102 | using (MemoryStream memory = new MemoryStream()) 103 | { 104 | qrCodeImage.Save(memory, System.Drawing.Imaging.ImageFormat.Bmp); 105 | memory.Position = 0; 106 | BitmapImage bitmapimage = new BitmapImage(); 107 | bitmapimage.BeginInit(); 108 | bitmapimage.StreamSource = memory; 109 | bitmapimage.CacheOption = BitmapCacheOption.OnLoad; 110 | bitmapimage.EndInit(); 111 | 112 | QRCode = bitmapimage; 113 | } 114 | } 115 | catch (FormatException ex) 116 | { 117 | Errors = $"Invalid input format. Exception details: {ex.Message}"; 118 | QRCode = null; 119 | } 120 | catch (Exception ex) 121 | { 122 | Errors = $"An unexpected exception of type {ex.GetType()} was thrown with message: {ex.Message}"; 123 | QRCode = null; 124 | } 125 | } 126 | 127 | private byte[] GetInput() 128 | { 129 | switch (SelectedInEncoder) 130 | { 131 | case Encoders.UTF8: 132 | return Encoding.UTF8.GetBytes(RawTx); 133 | case Encoders.Base16: 134 | return Base16.ToByteArray(RawTx); 135 | case Encoders.Base58: 136 | return b58enc.Decode(RawTx); 137 | case Encoders.Base58Check: 138 | return b58enc.DecodeWithCheckSum(RawTx); 139 | case Encoders.Base43: 140 | return b43enc.Decode(RawTx); 141 | case Encoders.Base64: 142 | return Convert.FromBase64String(RawTx); 143 | default: 144 | throw new ArgumentException($"Encoder type {SelectedInEncoder} is not defined."); 145 | } 146 | } 147 | private string GetOutput(byte[] input) 148 | { 149 | switch (SelectedOutEncoder) 150 | { 151 | case Encoders.UTF8: 152 | return Encoding.UTF8.GetString(input); 153 | case Encoders.Base16: 154 | return input.ToBase16(); 155 | case Encoders.Base58: 156 | return b58enc.Encode(input); 157 | case Encoders.Base58Check: 158 | return b58enc.EncodeWithCheckSum(input); 159 | case Encoders.Base43: 160 | return b43enc.Encode(input); 161 | case Encoders.Base64: 162 | return Convert.ToBase64String(input); 163 | default: 164 | throw new ArgumentException($"Encoder type {SelectedInEncoder} is not defined."); 165 | } 166 | } 167 | 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/ViewModels/ScrAddressViewModel.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend; 7 | using BitcoinTransactionTool.Backend.Blockchain.Scripts; 8 | 9 | namespace BitcoinTransactionTool.ViewModels 10 | { 11 | public class ScrAddressViewModel : ScriptVMBase 12 | { 13 | public ScrAddressViewModel() 14 | { 15 | VmName = "Addresses"; 16 | Description = "Build PubkeyScript based on different addresses."; 17 | } 18 | 19 | 20 | 21 | private readonly Address addrManager = new Address(); 22 | public string Address { get; set; } 23 | 24 | 25 | 26 | public override bool SetOperations() 27 | { 28 | Errors = null; 29 | 30 | if (string.IsNullOrEmpty(Address)) 31 | { 32 | Errors = "Address can not be empty."; 33 | return false; 34 | } 35 | else if (addrManager.TryGetType(Address, out PubkeyScriptType scrType, out byte[] hash)) 36 | { 37 | PubkeyScript scr = new PubkeyScript(); 38 | switch (scrType) 39 | { 40 | case PubkeyScriptType.P2PKH: 41 | scr.SetToP2PKH(hash); 42 | break; 43 | case PubkeyScriptType.P2SH: 44 | scr.SetToP2SH(hash); 45 | break; 46 | case PubkeyScriptType.P2WPKH: 47 | scr.SetToP2WPKH(hash); 48 | break; 49 | case PubkeyScriptType.P2WSH: 50 | scr.SetToP2WSH(hash); 51 | break; 52 | default: 53 | Errors = "Undefined script type."; // This should never happen. 54 | return false; 55 | } 56 | 57 | OpsToAdd = scr.OperationList; 58 | return true; 59 | } 60 | else 61 | { 62 | Errors = "Invalid address type/format."; 63 | return false; 64 | } 65 | } 66 | 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/ViewModels/ScrArbitraryDataViewModel.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations; 7 | using BitcoinTransactionTool.Backend.Encoders; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Text; 12 | 13 | namespace BitcoinTransactionTool.ViewModels 14 | { 15 | public class ScrArbitraryDataViewModel : ScriptVMBase 16 | { 17 | public ScrArbitraryDataViewModel() 18 | { 19 | VmName = "Arbitrary data (OP_Return)"; 20 | Description = "Build OP_Return PubkeyScripts. " + 21 | "These scripts are used to store arbitrary data in bitcoin's blockchain, " + 22 | "burn coins in proof of burn, for OMNI layer and more."; 23 | 24 | EncodingList = Enum.GetValues(typeof(Encoders)).Cast(); 25 | } 26 | 27 | 28 | 29 | public enum Encoders 30 | { 31 | UTF8, 32 | Base16 33 | } 34 | 35 | public IEnumerable EncodingList { get; private set; } 36 | 37 | public Encoders SelectedEncoder { get; set; } 38 | public string Data { get; set; } 39 | 40 | 41 | public override bool SetOperations() 42 | { 43 | Errors = null; 44 | 45 | try 46 | { 47 | byte[] ba = new byte[0]; 48 | if (!string.IsNullOrEmpty(Data)) 49 | { 50 | switch (SelectedEncoder) 51 | { 52 | case Encoders.UTF8: 53 | ba = Encoding.UTF8.GetBytes(Data); 54 | break; 55 | case Encoders.Base16: 56 | if (!Base16.IsValid(Data)) 57 | { 58 | Errors = "Invalid base16 (hexadecimal) string."; 59 | return false; 60 | } 61 | else 62 | { 63 | ba = Base16.ToByteArray(Data); 64 | } 65 | break; 66 | default: 67 | Errors = "Undefined encoder."; 68 | return false; 69 | } 70 | } 71 | 72 | ReturnOp op = new ReturnOp(ba, true); 73 | OpsToAdd = new IOperation[1] { op }; 74 | } 75 | catch (Exception ex) 76 | { 77 | Errors = $"An unexpected error happened. Message: {ex.Message}"; 78 | return false; 79 | } 80 | 81 | return true; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/ViewModels/ScrMultiSigViewModel.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations; 7 | using BitcoinTransactionTool.Backend.Encoders; 8 | using BitcoinTransactionTool.Models; 9 | using System; 10 | using System.ComponentModel; 11 | using System.Linq; 12 | 13 | namespace BitcoinTransactionTool.ViewModels 14 | { 15 | public class ScrMultiSigViewModel : ScriptVMBase 16 | { 17 | public ScrMultiSigViewModel() 18 | { 19 | VmName = "Multi-sig redeem script"; 20 | Description = $"Build multi signature redeem script using given public keys.{Environment.NewLine}" + 21 | $"Validity of public keys are not currently being checked."; 22 | 23 | PubkeyList = new BindingList(); 24 | PubkeyList.ListChanged += PubkeyList_ListChanged; 25 | } 26 | 27 | private void PubkeyList_ListChanged(object sender, ListChangedEventArgs e) 28 | { 29 | if (e.ListChangedType == ListChangedType.ItemAdded || e.ListChangedType == ListChangedType.ItemDeleted) 30 | { 31 | N = PubkeyList.Count(); 32 | } 33 | } 34 | 35 | public BindingList PubkeyList { get; set; } 36 | 37 | 38 | private int _m; 39 | public int M 40 | { 41 | get => _m; 42 | set 43 | { 44 | if (_m != value) 45 | { 46 | if (value > N) 47 | { 48 | _m = N; 49 | RaisePropertyChanged(nameof(M)); 50 | } 51 | else 52 | { 53 | SetField(ref _m, value); 54 | } 55 | } 56 | } 57 | } 58 | 59 | private int _n; 60 | public int N 61 | { 62 | get => _n; 63 | set => SetField(ref _n, value); 64 | } 65 | 66 | 67 | public override bool SetOperations() 68 | { 69 | Errors = null; 70 | 71 | if (PubkeyList.Count() == 0) 72 | { 73 | Errors = "At least one public key is needed."; 74 | return false; 75 | } 76 | else if (PubkeyList.Any(x => x.HasErrors)) 77 | { 78 | Errors = "Invalid public key was found."; 79 | return false; 80 | } 81 | else 82 | { 83 | // OP_m | pub1 | pub2 | ... | pub(n) | OP_n | OP_CheckMultiSig 84 | IOperation[] ops = new IOperation[N + 3]; 85 | 86 | ops[0] = new PushDataOp(M); 87 | ops[N + 1] = new PushDataOp(N); 88 | ops[N + 2] = new CheckMultiSigOp(); 89 | 90 | int i = 1; 91 | foreach (var item in PubkeyList) 92 | { 93 | ops[i++] = new PushDataOp(Base16.ToByteArray(item.PubKey)); 94 | } 95 | 96 | OpsToAdd = ops; 97 | 98 | return true; 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/ViewModels/ScriptVMBase.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend.Blockchain.Scripts.Operations; 7 | using BitcoinTransactionTool.Backend.MVVM; 8 | using System.Collections.Generic; 9 | 10 | namespace BitcoinTransactionTool.ViewModels 11 | { 12 | public abstract class ScriptVMBase : ViewModelBase 13 | { 14 | public string VmName { get; protected set; } 15 | public string Description { get; protected set; } 16 | 17 | 18 | private IEnumerable _ops; 19 | public IEnumerable OpsToAdd 20 | { 21 | get => _ops; 22 | set => SetField(ref _ops, value); 23 | } 24 | 25 | public abstract bool SetOperations(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/ViewModels/TxJsonViewModel.cs: -------------------------------------------------------------------------------- 1 | // Bitcoin Transaction Tool 2 | // Copyright (c) 2017 Coding Enthusiast 3 | // Distributed under the MIT software license, see the accompanying 4 | // file LICENCE or http://www.opensource.org/licenses/mit-license.php. 5 | 6 | using BitcoinTransactionTool.Backend; 7 | using BitcoinTransactionTool.Backend.Blockchain; 8 | using BitcoinTransactionTool.Backend.Encoders; 9 | using BitcoinTransactionTool.Backend.MVVM; 10 | using Newtonsoft.Json; 11 | using System; 12 | 13 | namespace BitcoinTransactionTool.ViewModels 14 | { 15 | public class TxJsonViewModel : InpcBase 16 | { 17 | /// 18 | /// String representing the raw transaction in hex format. 19 | /// 20 | public string RawTx 21 | { 22 | get { return _rawTx; } 23 | set 24 | { 25 | if (SetField(ref _rawTx, value)) 26 | { 27 | SetJson(); 28 | } 29 | } 30 | } 31 | private string _rawTx; 32 | 33 | 34 | /// 35 | /// Transaction in Json formatet string 36 | /// 37 | public string TxJson 38 | { 39 | get { return _txJson; } 40 | set { SetField(ref _txJson, value); } 41 | } 42 | private string _txJson; 43 | 44 | 45 | 46 | internal static JsonSerializerSettings jSetting = new JsonSerializerSettings 47 | { 48 | Converters = { new ByteArrayHexConverter(true), new TransactionLocktimeConverter(), new TransactionScriptConverter() }, 49 | ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor 50 | }; 51 | private void SetJson() 52 | { 53 | if (!Base16.IsValid(_rawTx)) 54 | { 55 | TxJson = "Invalid hex."; 56 | } 57 | else 58 | { 59 | Transaction tx = new Transaction(); 60 | int offset = 0; 61 | 62 | TxJson = tx.TryDeserialize(Base16.ToByteArray(_rawTx), ref offset, out string error) 63 | ? JsonConvert.SerializeObject(tx, Formatting.Indented, jSetting) 64 | : "Error while deserializing transaction:" + Environment.NewLine + error; 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /BitcoinTransactionTool/Views/QrView.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | 22 | 26 | 27 | 28 | 32 | 33 |