예제 #1
0
        int IComparable.CompareTo(object obj)         //sortable by value
        {
            UTXO x = (UTXO)obj;

            if (this.Value == x.Value)
            {
                return(0);
            }
            return(this.Value > x.Value ? 1 : -1);
        }
예제 #2
0
        //parse json UTXO response
        public static UTXO[] ParseUTXO(string msg)
        {
            List <UTXO> lst = new List <UTXO>();

            /*
             * {"jsonrpc": "2.0", "id": "1", "result":
             * [{"tx_hash": "60c21462d1ddbac55ed34f205b9776303953c2b74de1f4283630e69db78d65ec", "tx_pos": 1, "height": 1260557, "value": 129967000},
             * {"tx_hash": "04fa60e351ffedff984e7cad9697a532dd6dc97966ed64b26919cc1741639861", "tx_pos": 0, "height": 1261826, "value": 16230000},
             * {"tx_hash": "70c3f2ff2721846bac77bf8aad863efdbc20ed0cc2f59dda6d7dfd02682c2805", "tx_pos": 0, "height": 1261827, "value": 32480000}]
             * }
             */
            msg = msg.Replace("\"", "").Replace(" ", "");

            /*
             * {jsonrpc:2.0,id:1,result:
             * [{tx_hash:60c21462d1ddbac55ed34f205b9776303953c2b74de1f4283630e69db78d65ec,tx_pos:1,height:1260557,value:129967000},
             * {tx_hash:04fa60e351ffedff984e7cad9697a532dd6dc97966ed64b26919cc1741639861,tx_pos:0,height:1261826,value:16230000},
             * {tx_hash:70c3f2ff2721846bac77bf8aad863efdbc20ed0cc2f59dda6d7dfd02682c2805,tx_pos:0,height:1261827,value:32480000}]
             * }
             */
            int pos = 0;

            while (true)
            {
                pos = msg.IndexOf("tx_hash", pos);
                if (pos < 0)
                {
                    break;
                }
                int      pos2    = msg.IndexOf("}", pos) - 1;
                string   oneutxo = msg.Substring(pos, pos2 - pos + 1);               //tx_hash:60c21462d1ddbac55ed34f205b9776303953c2b74de1f4283630e69db78d65ec,tx_pos:1,height:1260557,value:129967000
                string[] vals    = oneutxo.Split(',');
                UTXO     x       = new UTXO();
                x.Tx_hash = vals[0].Split(':')[1];                           //tx_hash:60c21462d1ddbac55ed34f205b9776303953c2b74de1f4283630e69db78d65ec
                x.Tx_pos  = int.Parse(vals[1].Split(':')[1]);                //tx_pos:1
                x.Height  = int.Parse(vals[2].Split(':')[1]);                //height:1260557
                x.Value   = int.Parse(vals[3].Split(':')[1]);                //value:129967000 (satoshi)
                lst.Add(x);
                pos = pos2;
            }
            UTXO[] arr = lst.ToArray();
            Array.Sort(arr);             //smallest value first
            return(arr);
        }
예제 #3
0
        //take in tx parameters, return tx object
        public static TxSerial CreateTx(string extPubKey, string pubToAddr, string chgAddr, int walletId, long satToSend, long fee, bool testnet)
        {
            CheckNullOrEmpty(new object[] { extPubKey, pubToAddr, ElectrumXhost },
                             new string[] { "extPubKey", "pubToAddr", "ElectrumXhost" });

            string err = "";

            if (satToSend == 0)
            {
                err += "satoshiToSend = 0, ";
            }
            if (fee == 0)
            {
                err += "satoshiFee = 0, ";
            }
            if (err != "")
            {
                throw new Exception("[CreateTx] " + err);
            }

            //get first 100+100 child address from ext pub key
            List <Tuple <string, string> > recAddrList = GetDerivedKeys(extPubKey, 0, 20, false, testnet);         //receive addresses
            List <Tuple <string, string> > chgAddrList = GetDerivedKeys(extPubKey, 0, 20, true, testnet);          //change addresses

            //TODO - create process for getting next change address, so address never used twice
            if (chgAddr == null || chgAddr == "")             //get first chg addr for extPubKey
            {
                chgAddr = chgAddrList.First().Item1;
            }

            //server status check
            string info = ElectrumX.GetServerInfo(ElectrumXhost, ElectrumXport);

            if (info == null)
            {
                throw new Exception("[CreateTx] ElectrumX Server Check Failed");
            }

            string[] recAddrListAddr = new string[recAddrList.Count];            //short address
            string[] recAddrListExt  = new string[recAddrList.Count];            //long address
            int      ctr             = 0;

            foreach (var t in recAddrList)
            {
                recAddrListAddr[ctr++] = t.Item1;                 //short
            }
            ctr = 0;
            foreach (var t in recAddrList)
            {
                recAddrListExt[ctr++] = t.Item2;                 //long - hash
            }
            string[] chgAddrListAddr = new string[recAddrList.Count];
            string[] chgAddrListExt  = new string[recAddrList.Count];
            ctr = 0;
            foreach (var t in chgAddrList)
            {
                chgAddrListAddr[ctr++] = t.Item1;
            }
            ctr = 0;
            foreach (var t in chgAddrList)
            {
                chgAddrListExt[ctr++] = t.Item2;
            }

            //get all UTXOs (unspent inputs) from receive addresses
            UTXO[] recUTXOs = ElectrumX.GetUTXOs(recAddrList, ElectrumXhost, ElectrumXport);
            UTXO.SetAddressType(recUTXOs, 0);             //receiver
            //get all UTXOs (unspent inputs) from change addresses
            UTXO[] chgUTXOs = ElectrumX.GetUTXOs(chgAddrList, ElectrumXhost, ElectrumXport);
            UTXO.SetAddressType(chgUTXOs, 1);             //change

            //start new tx
            TransactionBuilder bldr = new TransactionBuilder();

            bldr.Send(new BitcoinPubKeyAddress(pubToAddr), Money.Satoshis(satToSend)); //amount to send to recipient
            bldr.SetChange(new BitcoinPubKeyAddress(chgAddr));                         //send change to this address
            bldr.SendFees(Money.Satoshis(fee));                                        //miner (tx) fee

            //collect all UTXOs
            List <UTXO> allUTXOs = new List <UTXO>();

            allUTXOs.AddRange(recUTXOs);
            allUTXOs.AddRange(chgUTXOs);

            List <ICoin> lstTxCoins = new List <ICoin>();           //Coin is a UTXO

            //add new coin for each UTXO
            foreach (UTXO x in allUTXOs)             //tx builder will select coins from this list
            {
                BitcoinPubKeyAddress fromAddr = new BitcoinPubKeyAddress(x.Address);
                NBitcoin.Coin        cn       = null;
                //create new coin from UTXO
                bldr.AddCoins(cn = new NBitcoin.Coin(
                                  new OutPoint(new uint256(x.Tx_hash), x.Tx_pos),              //tx that funded wallet, spend this coin
                                  new TxOut(Money.Satoshis(x.Value), fromAddr.ScriptPubKey))); //specify full coin amount, else SetChange ignored
                lstTxCoins.Add(cn);                                                            //add coin to transaction, may not be used
                x.tmp = cn;                                                                    //link UTXO with coin
            }

            List <UTXO> usedUTXOs = new List <UTXO>();              //coins actually used in tx

            NBitcoin.Transaction tx = bldr.BuildTransaction(false); //sort\filter coins, some coins will not be needed\used
            //coin objects not stored in tx, so we need to determine which coins were used
            //scan tx inputs for matching coins, ignore other coins
            foreach (UTXO u in allUTXOs)
            {
                foreach (TxIn i in tx.Inputs)
                {
                    if (i.PrevOut == ((NBitcoin.Coin)u.tmp).Outpoint) //this coin in tx
                    {
                        usedUTXOs.Add(u);                             //this UTXO will be used\spent in tx
                    }
                }
            }
            //populate return object
            TxSerial txs = new TxSerial()
            {
                SendAmt      = satToSend,
                Fee          = fee,
                ExtPublicKey = extPubKey,
                ToAddress    = pubToAddr,
                ChgAddress   = chgAddr,
                WalletId     = walletId
            };
            txs.ExtPublicKey = extPubKey;

            foreach (UTXO u in usedUTXOs)
            {
                u.tmp = null;                 //don't serialize coin object, will rebuild coins in signing process
            }
            txs.InputUTXOs = new List <UTXO>();
            txs.InputUTXOs.AddRange(usedUTXOs);
            //string jsn = Newtonsoft.Json.JsonConvert.SerializeObject(txs, Newtonsoft.Json.Formatting.Indented);
            return(txs);
        }