//scan derived addresses for any balance public static long GetExtendedBalance(string extPubKey, uint start, uint cnt, uint stopAfter, bool testnet) { CheckNullOrEmpty(new object[] { extPubKey }, new string[] { "extPubKey" }); List <Tuple <string, string> > recAddrList = GetDerivedKeys(extPubKey, start, cnt, false, testnet); //receive addresses List <Tuple <string, string> > chgAddrList = GetDerivedKeys(extPubKey, start, cnt, true, testnet); //change addresses string[] recAddrListAddr = new string[recAddrList.Count]; //short address - myB9vrgbz4THVf.... string[] recAddrListExt = new string[recAddrList.Count]; //extended address - tpubD6NzVbkrYh..... int ctr = 0; foreach (var t in recAddrList) { recAddrListAddr[ctr++] = t.Item1; //short - address } ctr = 0; foreach (var t in recAddrList) { recAddrListExt[ctr++] = t.Item2; //long - public key } 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; } long bal = 0; //add up all UTXOs (unspent inputs) in address list MainWindow.MainWin.UpdateStatus(">>>> Receive Addresses"); bal += ElectrumX.GetBalance(recAddrListAddr, stopAfter, ElectrumXhost, ElectrumXport); MainWindow.MainWin.UpdateStatus(">>>> Change Addresses"); bal += ElectrumX.GetBalance(chgAddrListAddr, stopAfter, ElectrumXhost, ElectrumXport); return(bal); }
//get all unspent inputs for extended public key public static UTXO[] GetExtendedUTXOs(string extPublicKey, uint start, uint maxcnt, bool testnet) { CheckNullOrEmpty(new object[] { extPublicKey }, new string[] { "extPublicKey" }); //get child keys for extended public key List <Tuple <string, string> > keysRec = GetDerivedKeys(extPublicKey, start, maxcnt, false, testnet); //receive addresses List <Tuple <string, string> > keysChg = GetDerivedKeys(extPublicKey, start, maxcnt, true, testnet); //change addresses List <UTXO> lst = new List <UTXO>(); //use ElectrumX server to get all unspent inputs lst.AddRange(ElectrumX.GetUTXOs(keysRec, ElectrumXhost, ElectrumXport)); lst.AddRange(ElectrumX.GetUTXOs(keysChg, ElectrumXhost, ElectrumXport)); //we actually used maxcnt twice (for receiving addresses and change addresses), so may need to truncate if (lst.Count > maxcnt) { lst.Resize((int)maxcnt); } return(lst.ToArray()); }
public static long EstimateFee() { return(ElectrumX.EstimateFee(20, ElectrumXhost, ElectrumXport)); }
//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); }