Exemple #1
0
        private static string BuildScriptPub(string addr)
        {
            string hash160 = BitcoinConversions.Base58ToHash160(addr);

            return(ByteArray.ConcatArrays(
                       new byte[] { (byte)OPCodes.OP_DUP, (byte)OPCodes.OP_HASH160 },
                       new byte[] { (byte)(hash160.Length / 2) },
                       Base16.ToByteArray(hash160),
                       new byte[] { (byte)OPCodes.OP_EQUALVERIFY, (byte)OPCodes.OP_CHECKSIG }).ToBase16());
        }
        private void MakeTx()
        {
            List <UTXO> uList = new List <UTXO>();

            foreach (var item in TxInList)
            {
                UTXO u = new UTXO();
                u.TxHash   = item.TxId;
                u.OutIndex = item.OutIndex;
                if (BTx.Status == BitcoinTransaction.TxStatus.Signed)
                {
                    int    pubKeyLength = 65;
                    string pubKey       = item.ScriptSig.Substring((item.ScriptSigLength * 2) - (pubKeyLength + 1));
                    u.Address        = BitcoinConversions.PubKeyToBase58(pubKey);
                    u.AddressHash160 = BitcoinConversions.ByteArrayToHex(BitcoinConversions.PubKeyToHash160(pubKey));
                }
                else
                {
                    var addr = GetAddressFromScript(item.ScriptSig);
                    if (string.IsNullOrEmpty(addr))
                    {
                        u.Address        = string.Empty;
                        u.AddressHash160 = string.Empty;
                    }
                    else
                    {
                        u.Address        = addr;
                        u.AddressHash160 = BitcoinConversions.Base58ToHash160(addr);
                    }
                }

                uList.Add(u);
            }

            try
            {
                UInt32 lockTime = 0;
                RawTx = Transaction.CreateRawTx(uList, ReceiveList.ToList(), lockTime, SelectedWalletType);
            }
            catch (Exception ex)
            {
                RawTx = string.Empty;
                MessageBox.Show(ex.Message);
            }
        }
Exemple #3
0
        /// <summary>
        /// Makes ScriptSig based on wallet type.
        /// <para/> INCOMPLETE!
        /// </summary>
        /// <param name="addr">Hes string to put inside of ScriptSig.</param>
        /// <param name="type">Type of wallet that is supposed to sign this transaction.</param>
        /// <returns>ScriptSig</returns>
        public static string BuildScriptSig(string addr, WalletType type)
        {
            string hash160 = BitcoinConversions.Base58ToHash160(addr);

            switch (type)
            {
            case WalletType.Electrum:
                //01 ff 16 fd 00
                return(ByteArray.ConcatArrays(
                           new byte[] { 1, (byte)OPCodes.OP_INVALIDOPCODE, 16, (byte)OPCodes.OP_PUBKEYHASH, 0 },
                           Base16.ToByteArray(hash160)
                           ).ToBase16());

            case WalletType.Normal:
            case WalletType.Core:
            default:
                return(BuildScriptPub(addr));
            }
        }
        /// <summary>
        /// Creates a Raw Unsigned bitcoin transaction Transaction.
        /// <para/> Sources:
        /// <para/> 1. https://bitcoin.stackexchange.com/questions/32628/redeeming-a-raw-transaction-step-by-step-example-required
        /// <para/> 2. https://bitcoin.org/en/developer-reference#raw-transaction-format
        /// <para/> 3. https://bitcoin.org/en/developer-examples#simple-raw-transaction
        /// </summary>
        /// <param name="txToSpend">List of UTXOs to spend.</param>
        /// <param name="receiveAddr">List of receiving addresses and the amount to be paid to each.</param>
        /// <param name="wallet">Type of the wallet (Electrum does not recognize normal type of scriptSig placeholder).</param>
        /// <returns>Rat unsigned transaction string.</returns>
        public static string CreateRawTx(List <UTXO> txToSpend, List <ReceivingAddress> receiveAddr, UInt32 lockTime, WalletType wallet)
        {
            StringBuilder rawTx = new StringBuilder();

            // 1) 4 byte - version
            UInt32 version = 1;

            rawTx.Append(NumberConversions.IntToHex(version, 4));

            // 2) ? byte - tx_in count (compactSize uint)
            int txInCount = txToSpend.Count;

            rawTx.Append(NumberConversions.MakeCompactSize((UInt64)txInCount));

            for (int i = 0; i < txInCount; i++)
            {
                // 3) 32 byte - TX hash (reverse)
                string txToSend = txToSpend[i].TxHash;
                rawTx.Append(ReverseTx(txToSend));

                // 4) 4 byte - output Index
                UInt32 outputIndex = txToSpend[i].OutIndex;
                rawTx.Append(NumberConversions.IntToHex(outputIndex, 4));

                // 5) ? byte - scriptSig length (compactSize uint) (Maximum value is 10,000 bytes)
                //    Can be from 0 and up. Will be replaced by actual scriptSig with another length.
                //    Format can be different based on the client which will be used for signing.
                if (string.IsNullOrEmpty(txToSpend[i].AddressHash160) && wallet != WalletType.Core)
                {
                    throw new Exception(string.Format("No address was found. Set wallet type to Core."));
                }
                string scriptSig = BuildScript(txToSpend[i].AddressHash160, wallet);
                rawTx.Append(NumberConversions.IntToHex((UInt64)(scriptSig.Length / 2), 1));

                // 6) ? byte - scriptSig which is filled with scriptPubkey temporarily (20 is half the length of address hash160)
                rawTx.Append(scriptSig);

                //7) 4 byte - sequence - max is 0xffffffff - can change for RBF transactions
                // Ref:
                // https://bitcoin.stackexchange.com/questions/2025/what-is-txins-sequence
                UInt32 sequence = UInt32.MaxValue;
                rawTx.Append(NumberConversions.IntToHex(sequence, 4));
            }

            //8) ? byte - tx_out count (compactSize uint)
            int txOutCount = receiveAddr.Count;

            rawTx.Append(NumberConversions.MakeCompactSize((UInt64)txOutCount));

            foreach (var item in receiveAddr)
            {
                //9) 8 byte - amout to transfer
                UInt64 amount = item.PaymentSatoshi;
                rawTx.Append(NumberConversions.IntToHex(amount, 8));

                //10) ? byte - pk_script length (compactSize uint)
                string itemHash     = BitcoinConversions.Base58ToHash160(item.Address);
                string outputScript = BuildScript(itemHash, WalletType.Normal);
                rawTx.Append(NumberConversions.MakeCompactSize((UInt64)outputScript.Length / 2));

                //11) ? byte - pk_script
                rawTx.Append(outputScript);
            }

            //12) 4 byte - lock time
            // * If less than 500 million, locktime is parsed as a block height. The transaction can be added to any block which has this height or higher.
            // * If greater than or equal to 500 million, locktime is parsed using the Unix epoch time format (the number of seconds elapsed since 1970-01-01T00:00 UTC—currently over 1.395 billion). The transaction can be added to any block whose block time is greater than the locktime.
            rawTx.Append(NumberConversions.IntToHex(lockTime, 4));

            return(rawTx.ToString());
        }