Ejemplo n.º 1
0
        /// <inheritdoc cref="AddNewAccount(string, string, byte[], Network, DateTimeOffset)"/>
        /// <summary>
        /// Adds an account to the current account root using extended public key and account index.
        /// </summary>
        /// <param name="accountExtPubKey">The extended public key for the account.</param>
        /// <param name="accountIndex">The zero-based account index.</param>
        public HdAccount AddNewAccount(ExtPubKey accountExtPubKey, int accountIndex, Network network, DateTimeOffset accountCreationTime)
        {
            ICollection <HdAccount> hdAccounts = this.Accounts.ToList();

            if (hdAccounts.Any(a => a.Index == accountIndex))
            {
                throw new WalletException("There is already an account in this wallet with index: " + accountIndex);
            }

            if (hdAccounts.Any(x => x.ExtendedPubKey == accountExtPubKey.ToString(network)))
            {
                throw new WalletException("There is already an account in this wallet with this xpubkey: " +
                                          accountExtPubKey.ToString(network));
            }

            string accountHdPath = HdOperations.GetAccountHdPath((int)this.CoinType, accountIndex);

            var newAccount = new HdAccount
            {
                Index             = accountIndex,
                ExtendedPubKey    = accountExtPubKey.ToString(network),
                ExternalAddresses = new List <HdAddress>(),
                InternalAddresses = new List <HdAddress>(),
                Name         = $"account {accountIndex}",
                HdPath       = accountHdPath,
                CreationTime = accountCreationTime
            };

            hdAccounts.Add(newAccount);
            this.Accounts = hdAccounts;

            return(newAccount);
        }
Ejemplo n.º 2
0
        /// <inheritdoc />
        public void ImportMemberKey(string password, string mnemonic)
        {
            Guard.NotEmpty(password, nameof(password));
            Guard.NotEmpty(mnemonic, nameof(mnemonic));

            // Get the extended key.
            ExtKey extendedKey;

            try
            {
                extendedKey = HdOperations.GetExtendedKey(mnemonic);
            }
            catch (NotSupportedException ex)
            {
                this.logger.LogTrace("Exception occurred: {0}", ex.ToString());
                this.logger.LogTrace("(-)[EXCEPTION]");

                if (ex.Message == "Unknown")
                {
                    throw new WalletException("Please make sure you enter valid mnemonic words.");
                }

                throw;
            }

            // Create a wallet file.
            string encryptedSeed = extendedKey.PrivateKey.GetEncryptedBitcoinSecret(password, this.network).ToWif();

            this.Wallet.EncryptedSeed = encryptedSeed;
            this.SaveWallet();

            this.logger.LogTrace("(-)");
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Create an account for a specific account index and account name pattern.
        /// </summary>
        /// <param name="password">The password used to decrypt the wallet's encrypted seed.</param>
        /// <param name="encryptedSeed">The encrypted private key for this wallet.</param>
        /// <param name="chainCode">The chain code for this wallet.</param>
        /// <param name="network">The network for which this account will be created.</param>
        /// <param name="accountCreationTime">Creation time of the account to be created.</param>
        /// <param name="newAccountIndex">The optional account index to use.</param>
        /// <param name="newAccountName">The optional account name to use.</param>
        /// <returns>A new HD account.</returns>
        public HdAccount CreateAccount(string password, string encryptedSeed, byte[] chainCode,
                                       Network network, DateTimeOffset accountCreationTime,
                                       int newAccountIndex, string newAccountName = null)
        {
            if (string.IsNullOrEmpty(newAccountName))
            {
                newAccountName = string.Format(Wallet.AccountNamePattern, newAccountIndex);
            }

            // Get the extended pub key used to generate addresses for this account.
            string    accountHdPath    = HdOperations.GetAccountHdPath((int)this.CoinType, newAccountIndex);
            Key       privateKey       = HdOperations.DecryptSeed(encryptedSeed, password, network);
            ExtPubKey accountExtPubKey = HdOperations.GetExtendedPublicKey(privateKey, chainCode, accountHdPath);

            return(new HdAccount
            {
                Index = newAccountIndex,
                ExtendedPubKey = accountExtPubKey.ToString(network),
                ExternalAddresses = new List <HdAddress>(),
                InternalAddresses = new List <HdAddress>(),
                Name = newAccountName,
                HdPath = accountHdPath,
                CreationTime = accountCreationTime
            });
        }
        /// <summary>
        /// Initializes the cross-chain transfer tests.
        /// </summary>
        /// <param name="network">The network to run the tests for.</param>
        public CrossChainTestBase(Network network = null, Network counterChainNetwork = null)
        {
            this.network             = network ?? FederatedPegNetwork.NetworksSelector.Regtest();
            this.counterChainNetwork = counterChainNetwork ?? Networks.Stratis.Regtest();
            this.federatedPegOptions = new FederatedPegOptions(counterChainNetwork);

            NetworkRegistration.Register(this.network);

            this.loggerFactory = Substitute.For <ILoggerFactory>();
            this.nodeLifetime  = new NodeLifetime();
            this.logger        = Substitute.For <ILogger>();
            this.signals       = Substitute.For <ISignals>();
            this.asyncProvider = new AsyncProvider(this.loggerFactory, this.signals, this.nodeLifetime);
            this.loggerFactory.CreateLogger(null).ReturnsForAnyArgs(this.logger);
            this.dateTimeProvider                   = DateTimeProvider.Default;
            this.opReturnDataReader                 = new OpReturnDataReader(this.loggerFactory, this.federatedPegOptions);
            this.blockRepository                    = Substitute.For <IBlockRepository>();
            this.fullNode                           = Substitute.For <IFullNode>();
            this.withdrawalTransactionBuilder       = Substitute.For <IWithdrawalTransactionBuilder>();
            this.federationWalletManager            = Substitute.For <IFederationWalletManager>();
            this.federationWalletSyncManager        = Substitute.For <IFederationWalletSyncManager>();
            this.FederationWalletTransactionHandler = Substitute.For <IFederationWalletTransactionHandler>();
            this.walletFeePolicy                    = Substitute.For <IWalletFeePolicy>();
            this.connectionManager                  = Substitute.For <IConnectionManager>();
            this.dBreezeSerializer                  = new DBreezeSerializer(this.network.Consensus.ConsensusFactory);
            this.ibdState                           = Substitute.For <IInitialBlockDownloadState>();
            this.wallet = null;
            this.federationGatewaySettings = Substitute.For <IFederationGatewaySettings>();
            this.ChainIndexer = new ChainIndexer(this.network);

            this.federationGatewaySettings.TransactionFee.Returns(new Money(0.01m, MoneyUnit.BTC));

            // Generate the keys used by the federation members for our tests.
            this.federationKeys = new[]
            {
                "ensure feel swift crucial bridge charge cloud tell hobby twenty people mandate",
                "quiz sunset vote alley draw turkey hill scrap lumber game differ fiction",
                "exchange rent bronze pole post hurry oppose drama eternal voice client state"
            }.Select(m => HdOperations.GetExtendedKey(m)).ToArray();

            SetExtendedKey(0);

            this.fundingTransactions = new List <Transaction>();

            this.blockDict = new Dictionary <uint256, Block>();
            this.blockDict[this.network.GenesisHash] = this.network.GetGenesis();

            this.blockRepository.GetBlocks(Arg.Any <List <uint256> >()).ReturnsForAnyArgs((x) =>
            {
                var hashes = x.ArgAt <List <uint256> >(0);
                var blocks = new List <Block>();
                for (int i = 0; i < hashes.Count; i++)
                {
                    blocks.Add(this.blockDict.TryGetValue(hashes[i], out Block block) ? block : null);
                }

                return(blocks);
            });
        }
Ejemplo n.º 5
0
        private ExtPubKey GetExtendedPublicKey(CoreNode node)
        {
            ExtKey    xPrivKey   = node.Mnemonic.DeriveExtKey(WalletPassphrase);
            Key       privateKey = xPrivKey.PrivateKey;
            ExtPubKey xPublicKey = HdOperations.GetExtendedPublicKey(privateKey, xPrivKey.ChainCode, KnownCoinTypes.Bitcoin, 0);

            return(xPublicKey);
        }
        private ExtPubKey GetExtendedPublicKey(string nodeName)
        {
            ExtKey    xPrivKey   = this.nodeGroupBuilder.NodeMnemonics[nodeName].DeriveExtKey(WalletPassword);
            Key       privateKey = xPrivKey.PrivateKey;
            ExtPubKey xPublicKey = HdOperations.GetExtendedPublicKey(privateKey, xPrivKey.ChainCode, (int)CoinType.Bitcoin, 0);

            return(xPublicKey);
        }
Ejemplo n.º 7
0
        public void ShouldProduceCorrectExtPubKey()
        {
            // This test is a replicate of 'should produce correct extpubkey' test in Angular (City Hub).
            var passphrase     = "";
            var recoveryPhrase = "mystery problem faith negative member bottom concert bundle asthma female process twelve";
            var walletPassword = "******";

            var network   = new CityMain();
            var chainCode = new byte[] { 166, 209, 155, 88, 182, 124, 193, 127, 139, 220, 152, 1, 213, 145, 245, 80, 118, 188, 53, 211, 33, 37, 158, 40, 118, 207, 42, 83, 219, 233, 188, 161 };

            // Intentionally blank lines to be
            // line-compatible with JavaScript unit test.

            // The master node is made without network information, always same no matter network.
            ExtKey    masterNode = HdOperations.GetExtendedKey(recoveryPhrase, passphrase);
            ExtPubKey extPubKey  = masterNode.Neuter();

            // masterNode in C# and JavaScript should both have the same chaincode at this step, verify:
            Assert.Equal(chainCode, masterNode.ChainCode);
            Assert.Equal(chainCode, extPubKey.ChainCode);

            // Get the private key in WIF format and verify.
            var xprv = masterNode.GetWif(network).ToWif();

            Assert.Equal("xprv9s21ZrQH143K3ignAgXxaBbyVbrCTuUJSHNrMwdTa7n4i1zpFsiWdRCerTWrKaZXVehZFbXcFtwnmndrzC1AVs1BueiycVSxXjMyhXHpBqx", xprv);

            // Get the public key in WIF format and verify.
            var xpub = extPubKey.GetWif(network).ToWif();

            Assert.Equal("xpub661MyMwAqRbcGCmFGi4xwKYi3dggsNC9oWJTAL358TK3apKxoR2mBDX8hkD1cUePJyzkkNWffsfZEzkExFXN1sNfJoVw161LfQyCuNVDadK", xpub);

            // Get the "root" address.
            var address = masterNode.PrivateKey.PubKey.GetAddress(network);

            // Ensure that the generated address is a City Chain address and not Bitcoin.
            Assert.Equal("CQtq75vu4bAceku6FmenWBh35i1Y4oskdu", address.ToString());

            var publicNode = masterNode.Derive(new KeyPath("m/44'/1926'/0'/0/0"));
            var changeNode = masterNode.Derive(new KeyPath("m/44'/1926'/0'/1/0"));

            Assert.Equal("CPtzM2XwLCVS3L6BFK1xYsCcGqgrgsxHrP", publicNode.PrivateKey.PubKey.GetAddress(network).ToString());
            Assert.Equal("CY35ZGxzZBYHKyNV4KWKunYLHsTWejVSdR", changeNode.PrivateKey.PubKey.GetAddress(network).ToString());

            // Get the first account in the HD wallet, this is same as the level stored in the wallet files.
            var accountNode      = masterNode.Derive(new KeyPath("m/44'/1926'/0'"));
            var accountExtPubKey = accountNode.Neuter().GetWif(network).ToWif();

            Assert.Equal("xpub6BwCLtuvjt6TZ495sJruY1UWPXg6ME9HA92ro75YDHvGpPKY6kQ6ifp6DEszRpJGMtdBvWBaSn4gQDTz4Ctm5m1BMLeFUh3F19mTXA4s3bE", accountExtPubKey);

            // Create a wallet file.
            string encryptedSeed = masterNode.PrivateKey.GetEncryptedBitcoinSecret(walletPassword, network).ToWif();

            Assert.Equal("6PYW8DRnFZSu3CVC3NfghKFSozZE8gmf76GmsGrrA9ciWbv6F6HhVSKkEQ", encryptedSeed);
        }
Ejemplo n.º 8
0
        /// Generates an HD public key derived from an extended public key.
        /// </summary>
        /// <param name="accountExtPubKey">The extended public key used to generate child keys.</param>
        /// <param name="index">The index of the child key to generate.</param>
        /// <param name="isChange">A value indicating whether the public key to generate corresponds to a change address.</param>
        /// <returns>
        /// An HD public key derived from an extended public key.
        /// </returns>

        public Script GeneratePublicKey(int hdPathIndex, Network network, bool isChange = false)
        {
            List <PubKey> derivedPubKeys = new List <PubKey>();

            foreach (var xpub in this.MultisigScheme.XPubs)
            {
                derivedPubKeys.Add(HdOperations.GeneratePublicKey(xpub, hdPathIndex, isChange, network));
            }
            var sortedkeys = LexographicalSort(derivedPubKeys);

            Script redeemScript = PayToMultiSigTemplate.Instance.GenerateScriptPubKey(this.MultisigScheme.Threashold, sortedkeys.ToArray());

            return(redeemScript);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Creates a number of additional addresses in the current account.
        /// </summary>
        /// <remarks>
        /// The name given to the account is of the form "account (i)" by default, where (i) is an incremental index starting at 0.
        /// According to BIP44, an account at index (i) can only be created when the account at index (i - 1) contains at least one transaction.
        /// </remarks>
        /// <param name="network">The network these addresses will be for.</param>
        /// <param name="addressesQuantity">The number of addresses to create.</param>
        /// <param name="isChange">Whether the addresses added are change (internal) addresses or receiving (external) addresses.</param>
        /// <returns>The created addresses.</returns>
        public IEnumerable <HdAddress> CreateAddresses(Network network, int addressesQuantity, bool isChange = false)
        {
            ICollection <HdAddress> addresses = isChange ? this.InternalAddresses : this.ExternalAddresses;

            // Get the index of the last address.
            int firstNewAddressIndex = 0;

            if (addresses.Any())
            {
                firstNewAddressIndex = addresses.Max(add => add.Index) + 1;
            }

            var addressesCreated = new List <HdAddress>();

            for (int i = firstNewAddressIndex; i < firstNewAddressIndex + addressesQuantity; i++)
            {
                // Retrieve the pubkey associated with the private key of this address index.
                PubKey pubkey = HdOperations.GeneratePublicKey(this.ExtendedPubKey, i, isChange);

                // Generate the P2PKH address corresponding to the pubkey.
                BitcoinPubKeyAddress    address    = pubkey.GetAddress(network);
                BitcoinWitPubKeyAddress witAddress = pubkey.GetSegwitAddress(network);

                // Add the new address details to the list of addresses.
                var newAddress = new HdAddress
                {
                    Index         = i,
                    HdPath        = HdOperations.CreateHdPath((int)this.GetCoinType(), this.Index, isChange, i),
                    ScriptPubKey  = address.ScriptPubKey,
                    Pubkey        = pubkey.ScriptPubKey,
                    Bech32Address = witAddress.ToString(),
                    Address       = address.ToString(),
                };

                addresses.Add(newAddress);
                addressesCreated.Add(newAddress);
            }

            if (isChange)
            {
                this.InternalAddresses = addresses;
            }
            else
            {
                this.ExternalAddresses = addresses;
            }

            return(addressesCreated);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Gets the extended private key for the given address.
        /// </summary>
        /// <param name="password">The password used to encrypt/decrypt sensitive info.</param>
        /// <param name="address">The address to get the private key for.</param>
        /// <returns>The extended private key.</returns>
        public ISecret GetExtendedPrivateKeyForAddress(string password, HdAddress address)
        {
            Guard.NotEmpty(password, nameof(password));
            Guard.NotNull(address, nameof(address));

            // Check if the wallet contains the address.
            if (!this.ContainsAddress(address))
            {
                throw new WalletException("Address not found on wallet.");
            }

            // get extended private key
            Key privateKey = HdOperations.DecryptSeed(this.EncryptedSeed, password, this.Network);

            return(HdOperations.GetExtendedPrivateKey(privateKey, this.ChainCode, address.HdPath, this.Network));
        }
Ejemplo n.º 11
0
        public void pubKeysDerivedFromExtendedPrivateAndPublicKeysMatch()
        {
            string password   = "******";
            string passphrase = password;

            string mnemonic = "chalk call anger chase endless level slow sleep coast left sand enter save bind curious puzzle stadium volume mixture shuffle hurry gas borrow believe";

            ExtKey extendedKey = HdOperations.GetExtendedKey(mnemonic, passphrase);

            string encryptedSeed = extendedKey.PrivateKey.GetEncryptedBitcoinSecret(password, this.Network).ToWif();
            Key    privateKey    = HdOperations.DecryptSeed(encryptedSeed, password, this.Network);

            string accountHdPath = HdOperations.GetAccountHdPath(COINTYPE, 0);
            string path          = HdOperations.CreateHdPath(COINTYPE, 0, false, 0);

            ExtPubKey accountExtPubKey = HdOperations.GetExtendedPublicKey(privateKey, extendedKey.ChainCode, accountHdPath);
            var       subjectPubKey    = HdOperations.GeneratePublicKey(accountExtPubKey.ToString(this.Network), 0, false, this.Network);

            var subjectPrivKey = HdOperations.GetExtendedPrivateKey(privateKey, extendedKey.ChainCode, path, this.Network);

            Assert.Equal(subjectPubKey.ScriptPubKey, subjectPrivKey.PrivateKey.PubKey.ScriptPubKey);
        }
Ejemplo n.º 12
0
 /// <summary>
 /// Gets the type of coin this account is for.
 /// </summary>
 /// <returns>A BIP44 CoinType.</returns>
 public int GetCoinType()
 {
     return(HdOperations.GetCoinType(this.HdPath));
 }
Ejemplo n.º 13
0
 /// <summary>
 /// Determines whether this is a change address or a receive address.
 /// </summary>
 /// <returns>
 ///   <c>true</c> if it is a change address; otherwise, <c>false</c>.
 /// </returns>
 public bool IsChangeAddress()
 {
     return(HdOperations.IsChangeAddress(this.HdPath));
 }