Exemple #1
0
        public static void TryUpdateLookAhead(string passphrase, X1WalletFile x1WalletFile)
        {
            if (string.IsNullOrWhiteSpace(passphrase))
            {
                return;
            }

            x1WalletFile.LookAhead.Clear();

            var decryptedSeed     = VCL.DecryptWithPassphrase(passphrase, x1WalletFile.HdSeed);
            var changeAddressGaps = GetIndexGaps(C.Change, x1WalletFile);

            foreach (var index in changeAddressGaps)
            {
                var generated = GeneratePubKeyHashAddress(decryptedSeed, passphrase, x1WalletFile.CoinType, C.Change, index);
                x1WalletFile.LookAhead[generated.Address] = generated;
            }

            var receiveAddressGaps = GetIndexGaps(C.External, x1WalletFile);

            foreach (var index in receiveAddressGaps)
            {
                var generated = GeneratePubKeyHashAddress(decryptedSeed, passphrase, x1WalletFile.CoinType, C.External, index);
                x1WalletFile.LookAhead[generated.Address] = generated;
            }

            x1WalletFile.SaveX1WalletFile(x1WalletFile.CurrentPath);
        }
        internal static ExportKeysResponse ExportKeys(ExportKeysRequest exportKeysRequest, IReadOnlyCollection <ISegWitAddress> addresses)
        {
            var header = new StringBuilder();

            header.AppendLine($"Starting export from wallet {exportKeysRequest.WalletName}, network {C.Network.Name} on {DateTime.UtcNow} UTC.");
            var errors = new StringBuilder();

            errors.AppendLine("Errors");
            var success = new StringBuilder();

            success.AppendLine("Exported Private Key (Hex); Unix Time UTC; IsChange; Address; Label:");
            int errorCount   = 0;
            int successCount = 0;

            try
            {
                header.AppendLine($"{addresses.Count} found in wallet.");

                var enc = new Bech32Encoder($"{C.Network.CoinTicker.ToLowerInvariant()}key");

                foreach (var a in addresses)
                {
                    try
                    {
                        var decryptedKey = VCL.DecryptWithPassphrase(exportKeysRequest.WalletPassphrase, a.GetEncryptedPrivateKey());
                        if (decryptedKey == null)
                        {
                            errorCount++;
                            header.AppendLine(
                                $"Address '{a.Address}'  could not be decrpted with this passphrase.");
                        }
                        else
                        {
                            var privateKey = enc.Encode(0, decryptedKey);
                            success.AppendLine($"{privateKey};{a.Address}");
                            successCount++;
                        }
                    }
                    catch (Exception e)
                    {
                        header.AppendLine($"Exception processing Address '{a.Address}': {e.Message}");
                    }
                }

                header.AppendLine($"{errorCount} errors occured.");
                header.AppendLine($"{successCount} addresses with private keys successfully exported.");
            }
            catch (Exception e)
            {
                errors.AppendLine(e.Message);
                return(new ExportKeysResponse {
                    Message = $"Export failed because an exception occured: {e.Message}"
                });
            }

            return(new ExportKeysResponse
            {
                Message = $"{header}{Environment.NewLine}{success}{Environment.NewLine}{errors}{Environment.NewLine}"
            });
        }
Exemple #3
0
        internal static void EnsureDefaultMultisigAddress(string passphrase, X1WalletFile x1WalletFile)
        {
            //if (x1WalletFile.ColdStakingAddresses.Count > 0)
            //    return;

            var decryptedSeed = VCL.DecryptWithPassphrase(passphrase, x1WalletFile.HdSeed);

            KeyMaterial myKeyMaterial = KeyHelper.CreateHdKeyMaterial(decryptedSeed, passphrase, C.Network.Consensus.CoinType, AddressType.MultiSig, C.External, 0);
            PubKey      myPubKey      = myKeyMaterial.GetKey(passphrase).PubKey.Compress();

            // other Key
            KeyMaterial otherKeyMaterial = KeyHelper.CreateHdKeyMaterial(decryptedSeed, passphrase, C.Network.Consensus.CoinType, AddressType.MultiSig, C.External, 1);
            var         otherPubKey      = otherKeyMaterial.GetKey(passphrase).PubKey.Compress();

            // The redeem script looks like:
            // 1 03fad6426522dbda5c5a9f8cab24a54ccc374517ad8790bf7e5a14308afc1bf77b 0340ecf2e20978075a49369e35269ecf0651d2f48061ebbf918f3eb1964051f65c 2 OP_CHECKMULTISIG
            Script redeemScript = PayToMultiSigTemplate.Instance.GenerateScriptPubKey(1, myPubKey, otherPubKey);

            // The address looks like:
            // odx1qvar8r29r8llzj53q5utmcewpju59263h38250ws33lp2q45lmalqg5lmdd
            string bech32ScriptAddress = redeemScript.WitHash.GetAddress(C.Network).ToString();

            // In P2SH payments, we refer to the hash of the Redeem Script as the scriptPubKey. It looks like:
            // 0 674671a8a33ffe295220a717bc65c19728556a3789d547ba118fc2a0569fdf7e
            Script scriptPubKey = redeemScript.WitHash.ScriptPubKey;
            var    scp          = scriptPubKey.ToString();


            var multiSigAddress = new MultiSigAddress
            {
                OwnKey             = myKeyMaterial, Address = bech32ScriptAddress, AddressType = AddressType.MultiSig,
                Label              = "Default 1-of-2 MultiSig", MaxSignatures = 2,
                LastSeenHeight     = null,
                SignaturesRequired = 1,
                RedeemScriptHex    = redeemScript.ToBytes().ToHexString(),
                ScriptPubKeyHex    = scriptPubKey.ToBytes().ToHexString(),
                OtherPublicKeys    = new System.Collections.Generic.Dictionary <string, string>(),
            };

            multiSigAddress.OtherPublicKeys.Add(otherPubKey.ToBytes().ToHexString(), "Bob");



            x1WalletFile.MultiSigAddresses[multiSigAddress.Address] = multiSigAddress;
        }
Exemple #4
0
        internal static void EnsureDefaultColdStakingAddress(string passphrase, X1WalletFile x1WalletFile)
        {
            //if (x1WalletFile.ColdStakingAddresses.Count > 0)
            //    return;

            var decryptedSeed = VCL.DecryptWithPassphrase(passphrase, x1WalletFile.HdSeed);

            var coldKey = KeyHelper.CreateHdKeyMaterial(decryptedSeed, passphrase, C.Network.Consensus.CoinType, AddressType.ColdStakingCold,
                                                        C.External, 0);

            var hotKey = KeyHelper.CreateHdKeyMaterial(decryptedSeed, passphrase, C.Network.Consensus.CoinType, AddressType.ColdStakingHot,
                                                       C.External, 0);

            PubKey coldPubKey = coldKey.GetKey(passphrase).PubKey.Compress();

            Key    hotPrivateKey = hotKey.GetKey(passphrase);
            PubKey hotPubKey     = hotPrivateKey.PubKey.Compress();

            Script csRedeemScript = ColdStakingScriptTemplate.Instance.GenerateScriptPubKey(hotPubKey.WitHash.AsKeyId(), coldPubKey.WitHash.AsKeyId());

            string csScriptAddress = csRedeemScript.WitHash.GetAddress(C.Network).ToString();

            Script csScriptAddressScriptPubKey = csRedeemScript.WitHash.ScriptPubKey;

            var csAddress = new ColdStakingAddress
            {
                ColdKey         = coldKey,
                HotKey          = hotKey,
                StakingKey      = hotPrivateKey.ToBytes(),
                Label           = "Default CS",
                AddressType     = AddressType.ColdStakingHot, // TODO: which address type?
                Address         = csScriptAddress,
                LastSeenHeight  = null,
                ScriptPubKeyHex = csScriptAddressScriptPubKey.ToBytes().ToHexString(),
                RedeemScriptHex = csRedeemScript.ToBytes().ToHexString()
            };

            if (csAddress.AddressType == AddressType.ColdStakingHot)
            {
                csAddress.StakingKey = hotPrivateKey.ToBytes();
            }

            x1WalletFile.ColdStakingAddresses[csAddress.Address] = csAddress;
        }
Exemple #5
0
        /// <summary>
        /// Wallet must be in perfect state, must be called locked.
        /// </summary>
        public static PubKeyHashAddress CreateAndInsertNewReceiveAddress(string label, string passphrase, X1WalletFile x1WalletFile)
        {
            if (!IsLabelUnique(label, x1WalletFile))
            {
                throw new X1WalletException($"The label '{label}' is already in use");
            }

            var nextIndex = GetNextIndex(C.External, x1WalletFile, out var _);

            var decryptedSeed = VCL.DecryptWithPassphrase(passphrase, x1WalletFile.HdSeed);
            var address       = GeneratePubKeyHashAddress(decryptedSeed, passphrase, x1WalletFile.CoinType, C.External, nextIndex);

            if (!x1WalletFile.PubKeyHashAddresses.TryAdd(address.Address, address))
            {
                throw new X1WalletException(HttpStatusCode.InternalServerError, $"Receive address {address.Address} already exists.");
            }

            x1WalletFile.SaveX1WalletFile(x1WalletFile.CurrentPath);
            return(address);
        }
        public void StartStaking(string passphrase)
        {
            if (this.isDisposing)
            {
                return;
            }

            Guard.NotNull(passphrase, nameof(passphrase));

            if (VCL.DecryptWithPassphrase(passphrase, base.GetPassphraseChallenge()) == null)
            {
                throw new X1WalletException(HttpStatusCode.Unauthorized, "The passphrase is not correct.");
            }

            base.SetStakingPassphrase(passphrase);


            if (this.stakingService == null)
            {
                this.stakingService = new StakingService(this, passphrase, this.nodeServices);
                this.stakingService.Start();
            }
        }
Exemple #7
0
        /// <summary>
        /// We assume that all PubKeyHashAddress addresses in this file are already used. Therefore this method
        /// should only be called when the wallet is fully up-to-date so that all used addresses are already discovered.
        /// </summary>
        public static List <PubKeyHashAddress> CreateAndInsertNewChangeAddresses(string passphrase, int addressesToCreate, X1WalletFile x1WalletFile)
        {
            var decryptedSeed = VCL.DecryptWithPassphrase(passphrase, x1WalletFile.HdSeed);

            var nextIndex = GetNextIndex(C.Change, x1WalletFile, out var _);

            var created      = 0;
            var newAddresses = new List <PubKeyHashAddress>(addressesToCreate);

            while (created < addressesToCreate)
            {
                var address = GeneratePubKeyHashAddress(decryptedSeed, passphrase, x1WalletFile.CoinType, C.Change, nextIndex);
                newAddresses.Add(address);
                if (!x1WalletFile.PubKeyHashAddresses.TryAdd(address.Address, address))
                {
                    Log.Logger.LogWarning($"Change address {address.Address} already existed - nothing was added.");
                }
                created++;
                nextIndex++;
            }

            x1WalletFile.SaveX1WalletFile(x1WalletFile.CurrentPath);
            return(newAddresses);
        }
Exemple #8
0
 public static Key GetPrivateKey(this SegWitCoin segWitCoin, string passphrase)
 {
     return(new Key(VCL.DecryptWithPassphrase(passphrase, segWitCoin.SegWitAddress.GetEncryptedPrivateKey())));
 }
        public static ImportKeysResponse ImportKeys(ImportKeysRequest importKeysRequest, byte[] passphraseChallenge)
        {
            if (importKeysRequest == null)
            {
                throw new ArgumentNullException(nameof(importKeysRequest));
            }
            if (importKeysRequest.WalletPassphrase == null)
            {
                throw new ArgumentNullException(nameof(importKeysRequest.WalletPassphrase));
            }
            if (importKeysRequest.Keys == null)
            {
                throw new ArgumentNullException(nameof(importKeysRequest.Keys));
            }

            var delimiters = new HashSet <char>();

            foreach (var c in importKeysRequest.Keys.Trim().ToCharArray())
            {
                if (char.IsWhiteSpace(c))
                {
                    delimiters.Add(c);
                }
            }

            var items        = importKeysRequest.Keys.Split(delimiters.ToArray());
            var possibleKeys = items.Where(i => i.Length == 52).Distinct().ToList();

            if (possibleKeys.Count == 0)
            {
                throw new X1WalletException(HttpStatusCode.BadRequest, "Input material cointained no keys.");
            }

            var test = VCL.DecryptWithPassphrase(importKeysRequest.WalletPassphrase, passphraseChallenge);

            if (test == null)
            {
                throw new X1WalletException(HttpStatusCode.Unauthorized,
                                            "Your passphrase is incorrect.");
            }
            var importedAddresses = new List <string>();

            var obsidianNetwork = new ObsidianNetwork();

            foreach (var candidate in possibleKeys)
            {
                try
                {
                    var secret     = new BitcoinSecret(candidate, obsidianNetwork);
                    var privateKey = secret.PrivateKey.ToBytes();
                    throw new NotImplementedException();
                    //var address = AddressHelper.CreateWithPrivateKey(privateKey, importKeysRequest.WalletPassphrase, AddressType.SingleKey);

                    //this.X1WalletFile.Addresses.Add(address.Address, address);
                    //importedAddresses.Add($"{secret.GetAddress()} -> {address.Address}");
                }
                catch (Exception e)
                {
                    Log.Logger.LogWarning($"Could not import '{candidate}' as key or address. {e.Message}");
                }
            }

            // this.X1WalletFile.SaveX1WalletFile(this.CurrentX1WalletFilePath);

            var response = new ImportKeysResponse
            {
                ImportedAddresses = importedAddresses, Message = $"Imported {importedAddresses.Count} addresses."
            };

            return(response);
        }
Exemple #10
0
 public static Key GetKey(this KeyMaterial keyMaterial, string passphrase)
 {
     return(new Key(VCL.DecryptWithPassphrase(passphrase, keyMaterial.EncryptedPrivateKey)));
 }