public void BuildTransactionFeeTooLowThrowsWalletException() { Assert.Throws <WalletException>(() => { var walletFeePolicy = new Mock <IWalletFeePolicy>(); walletFeePolicy.Setup(w => w.GetFeeRate(FeeType.Low.ToConfirmations())) .Returns(new FeeRate(0)); var wallet = WalletTestsHelpers.GenerateBlankWallet("myWallet1", "password"); var accountKeys = WalletTestsHelpers.GenerateAccountKeys(wallet, "password", "m/44'/0'/0'"); var spendingKeys = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "0/0"); var destinationKeys = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "0/1"); var changeKeys = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "1/0"); var address = new HdAddress { Index = 0, HdPath = $"m/44'/0'/0'/0/0", Address = spendingKeys.Address.ToString(), Pubkey = spendingKeys.PubKey.ScriptPubKey, ScriptPubKey = spendingKeys.Address.ScriptPubKey, Transactions = new List <TransactionData>() }; var chain = new ConcurrentChain(wallet.Network); WalletTestsHelpers.AddBlocksWithCoinbaseToChain(wallet.Network, chain, address); wallet.AccountsRoot.ElementAt(0).Accounts.Add(new HdAccount { Index = 0, Name = "account1", HdPath = "m/44'/0'/0'", ExtendedPubKey = accountKeys.ExtPubKey, ExternalAddresses = new List <HdAddress> { address }, InternalAddresses = new List <HdAddress> { new HdAddress { Index = 0, HdPath = $"m/44'/0'/0'/1/0", Address = changeKeys.Address.ToString(), Pubkey = changeKeys.PubKey.ScriptPubKey, ScriptPubKey = changeKeys.Address.ScriptPubKey, Transactions = new List <TransactionData>() } } }); var dataDir = "TestData/WalletTransactionHandlerTest/BuildTransactionFeeTooLowThrowsWalletException"; var walletManager = new WalletManager(this.LoggerFactory.Object, Network.Main, chain, NodeSettings.Default(), new Mock <WalletSettings>().Object, new DataFolder(new NodeSettings(args: new string[] { $"-datadir={dataDir}" }).DataDir), walletFeePolicy.Object, new Mock <IAsyncLoopFactory>().Object, new NodeLifetime(), DateTimeProvider.Default); var walletTransactionHandler = new WalletTransactionHandler(this.LoggerFactory.Object, walletManager, walletFeePolicy.Object, Network.Main); walletManager.Wallets.Add(wallet); var walletReference = new WalletAccountReference { AccountName = "account1", WalletName = "myWallet1" }; walletTransactionHandler.BuildTransaction(CreateContext(walletReference, "password", destinationKeys.PubKey.ScriptPubKey, new Money(7500), FeeType.Low, 0)); }); }
public void FundTransaction_Given__a_wallet_has_enough_inputs__When__adding_inputs_to_an_existing_transaction__Then__the_transaction_is_funded_successfully() { DataFolder dataFolder = CreateDataFolder(this); Wallet wallet = WalletTestsHelpers.GenerateBlankWallet("myWallet1", "password"); (ExtKey ExtKey, string ExtPubKey)accountKeys = WalletTestsHelpers.GenerateAccountKeys(wallet, "password", "m/44'/0'/0'"); (PubKey PubKey, BitcoinPubKeyAddress Address)spendingKeys = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "0/0"); (PubKey PubKey, BitcoinPubKeyAddress Address)destinationKeys1 = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "0/1"); (PubKey PubKey, BitcoinPubKeyAddress Address)destinationKeys2 = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "0/2"); (PubKey PubKey, BitcoinPubKeyAddress Address)destinationKeys3 = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "0/3"); var address = new HdAddress { Index = 0, HdPath = $"m/44'/0'/0'/0/0", Address = spendingKeys.Address.ToString(), Pubkey = spendingKeys.PubKey.ScriptPubKey, ScriptPubKey = spendingKeys.Address.ScriptPubKey, Transactions = new List <TransactionData>() }; // wallet with 4 coinbase outputs of 50 = 200 Bitcoin var chain = new ConcurrentChain(wallet.Network); WalletTestsHelpers.AddBlocksWithCoinbaseToChain(wallet.Network, chain, address, 4); wallet.AccountsRoot.ElementAt(0).Accounts.Add(new HdAccount { Index = 0, Name = "account1", HdPath = "m/44'/0'/0'", ExtendedPubKey = accountKeys.ExtPubKey, ExternalAddresses = new List <HdAddress> { address }, InternalAddresses = new List <HdAddress>() }); var walletFeePolicy = new Mock <IWalletFeePolicy>(); walletFeePolicy.Setup(w => w.GetFeeRate(FeeType.Low.ToConfirmations())).Returns(new FeeRate(20000)); var overrideFeeRate = new FeeRate(20000); var walletManager = new WalletManager(this.LoggerFactory.Object, this.Network, chain, NodeSettings.Default(), new Mock <WalletSettings>().Object, dataFolder, walletFeePolicy.Object, new Mock <IAsyncLoopFactory>().Object, new NodeLifetime(), DateTimeProvider.Default, this.scriptAddressReader); var walletTransactionHandler = new WalletTransactionHandler(this.LoggerFactory.Object, walletManager, walletFeePolicy.Object, this.Network, this.standardTransactionPolicy); walletManager.Wallets.Add(wallet); var walletReference = new WalletAccountReference { AccountName = "account1", WalletName = "myWallet1" }; // create a trx with 3 outputs 50 + 50 + 49 = 149 BTC var context = new TransactionBuildContext(this.Network) { AccountReference = walletReference, MinConfirmations = 0, FeeType = FeeType.Low, WalletPassword = "******", Recipients = new[] { new Recipient { Amount = new Money(50, MoneyUnit.BTC), ScriptPubKey = destinationKeys1.PubKey.ScriptPubKey }, new Recipient { Amount = new Money(50, MoneyUnit.BTC), ScriptPubKey = destinationKeys2.PubKey.ScriptPubKey }, new Recipient { Amount = new Money(49, MoneyUnit.BTC), ScriptPubKey = destinationKeys3.PubKey.ScriptPubKey } }.ToList() }; Transaction fundTransaction = walletTransactionHandler.BuildTransaction(context); Assert.Equal(4, fundTransaction.Inputs.Count); // 4 inputs Assert.Equal(4, fundTransaction.Outputs.Count); // 3 outputs with change // remove the change output fundTransaction.Outputs.Remove(fundTransaction.Outputs.First(f => f.ScriptPubKey == context.ChangeAddress.ScriptPubKey)); // remove 3 inputs they will be added back by fund transaction fundTransaction.Inputs.RemoveAt(3); fundTransaction.Inputs.RemoveAt(2); fundTransaction.Inputs.RemoveAt(1); Assert.Single(fundTransaction.Inputs); // 4 inputs Transaction fundTransactionClone = this.Network.CreateTransaction(fundTransaction.ToBytes()); var fundContext = new TransactionBuildContext(this.Network) { AccountReference = walletReference, MinConfirmations = 0, FeeType = FeeType.Low, WalletPassword = "******", Recipients = new List <Recipient>() }; fundContext.OverrideFeeRate = overrideFeeRate; walletTransactionHandler.FundTransaction(fundContext, fundTransaction); foreach (TxIn input in fundTransactionClone.Inputs) // all original inputs are still in the trx { Assert.Contains(fundTransaction.Inputs, a => a.PrevOut == input.PrevOut); } Assert.Equal(4, fundTransaction.Inputs.Count); // we expect 4 inputs Assert.Equal(4, fundTransaction.Outputs.Count); // we expect 4 outputs Assert.Equal(new Money(200, MoneyUnit.BTC) - fundContext.TransactionFee, fundTransaction.TotalOut); Assert.Contains(fundTransaction.Outputs, a => a.ScriptPubKey == destinationKeys1.PubKey.ScriptPubKey); Assert.Contains(fundTransaction.Outputs, a => a.ScriptPubKey == destinationKeys2.PubKey.ScriptPubKey); Assert.Contains(fundTransaction.Outputs, a => a.ScriptPubKey == destinationKeys3.PubKey.ScriptPubKey); }
private WalletTransactionHandlerTestContext SetupWallet() { DataFolder dataFolder = CreateDataFolder(this); Wallet wallet = WalletTestsHelpers.GenerateBlankWallet("myWallet1", "password"); (ExtKey ExtKey, string ExtPubKey)accountKeys = WalletTestsHelpers.GenerateAccountKeys(wallet, "password", "m/44'/0'/0'"); (PubKey PubKey, BitcoinPubKeyAddress Address)spendingKeys = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "0/0"); (PubKey PubKey, BitcoinPubKeyAddress Address)destinationKeys = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "0/1"); var address = new HdAddress { Index = 0, HdPath = $"m/44'/0'/0'/0/0", Address = spendingKeys.Address.ToString(), Pubkey = spendingKeys.PubKey.ScriptPubKey, ScriptPubKey = spendingKeys.Address.ScriptPubKey, Transactions = new List <TransactionData>() }; var chain = new ChainIndexer(wallet.Network); WalletTestsHelpers.AddBlocksWithCoinbaseToChain(wallet.Network, chain, address); TransactionData addressTransaction = address.Transactions.First(); wallet.AccountsRoot.ElementAt(0).Accounts.Add(new HdAccount { Index = 0, Name = "account1", HdPath = "m/44'/0'/0'", ExtendedPubKey = accountKeys.ExtPubKey, ExternalAddresses = new List <HdAddress> { address }, InternalAddresses = new List <HdAddress>() }); var walletFeePolicy = new Mock <IWalletFeePolicy>(); walletFeePolicy.Setup(w => w.GetFeeRate(FeeType.Low.ToConfirmations())) .Returns(new FeeRate(20000)); var walletManager = new WalletManager(this.LoggerFactory.Object, this.Network, chain, new WalletSettings(NodeSettings.Default(this.Network)), dataFolder, walletFeePolicy.Object, new Mock <IAsyncLoopFactory>().Object, new NodeLifetime(), DateTimeProvider.Default, this.scriptAddressReader); var walletTransactionHandler = new WalletTransactionHandler(this.LoggerFactory.Object, walletManager, walletFeePolicy.Object, this.Network, this.standardTransactionPolicy); walletManager.Wallets.Add(wallet); var walletReference = new WalletAccountReference { AccountName = "account1", WalletName = "myWallet1" }; return(new WalletTransactionHandlerTestContext { Wallet = wallet, AccountKeys = accountKeys, DestinationKeys = destinationKeys, AddressTransaction = addressTransaction, WalletTransactionHandler = walletTransactionHandler, WalletReference = walletReference }); }
public void BuildTransactionFeeTooLowDefaultsToMinimumFee() { var walletFeePolicy = new Mock <IWalletFeePolicy>(); walletFeePolicy.Setup(w => w.GetFeeRate(FeeType.Low.ToConfirmations())) .Returns(new FeeRate(0)); Wallet wallet = WalletTestsHelpers.GenerateBlankWallet("myWallet1", "password"); (ExtKey ExtKey, string ExtPubKey)accountKeys = WalletTestsHelpers.GenerateAccountKeys(wallet, "password", "m/44'/0'/0'"); (PubKey PubKey, BitcoinPubKeyAddress Address)spendingKeys = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "0/0"); (PubKey PubKey, BitcoinPubKeyAddress Address)destinationKeys = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "0/1"); (PubKey PubKey, BitcoinPubKeyAddress Address)changeKeys = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "1/0"); var address = new HdAddress { Index = 0, HdPath = $"m/44'/0'/0'/0/0", Address = spendingKeys.Address.ToString(), Pubkey = spendingKeys.PubKey.ScriptPubKey, ScriptPubKey = spendingKeys.Address.ScriptPubKey, Transactions = new List <TransactionData>() }; var chain = new ChainIndexer(wallet.Network); WalletTestsHelpers.AddBlocksWithCoinbaseToChain(wallet.Network, chain, address); wallet.AccountsRoot.ElementAt(0).Accounts.Add(new HdAccount { Index = 0, Name = "account1", HdPath = "m/44'/0'/0'", ExtendedPubKey = accountKeys.ExtPubKey, ExternalAddresses = new List <HdAddress> { address }, InternalAddresses = new List <HdAddress> { new HdAddress { Index = 0, HdPath = $"m/44'/0'/0'/1/0", Address = changeKeys.Address.ToString(), Pubkey = changeKeys.PubKey.ScriptPubKey, ScriptPubKey = changeKeys.Address.ScriptPubKey, Transactions = new List <TransactionData>() } } }); string dataDir = "TestData/WalletTransactionHandlerTest/BuildTransactionFeeTooLowThrowsWalletException"; var nodeSettings = new NodeSettings(network: this.Network, args: new string[] { $"-datadir={dataDir}" }); var walletManager = new WalletManager(this.LoggerFactory.Object, this.Network, chain, new WalletSettings(nodeSettings), new DataFolder(nodeSettings.DataDir), walletFeePolicy.Object, new Mock <IAsyncLoopFactory>().Object, new NodeLifetime(), DateTimeProvider.Default, this.scriptAddressReader); var walletTransactionHandler = new WalletTransactionHandler(this.LoggerFactory.Object, walletManager, walletFeePolicy.Object, this.Network, this.standardTransactionPolicy); walletManager.Wallets.Add(wallet); var walletReference = new WalletAccountReference { AccountName = "account1", WalletName = "myWallet1" }; TransactionBuildContext context = CreateContext(this.Network, walletReference, "password", destinationKeys.PubKey.ScriptPubKey, new Money(7500), FeeType.Low, 0); Transaction transaction = walletTransactionHandler.BuildTransaction(context); Assert.Equal(new Money(this.Network.MinTxFee, MoneyUnit.Satoshi), context.TransactionFee); }
public void FundTransaction_Given__a_wallet_has_enough_inputs__When__adding_inputs_to_an_existing_transaction__Then__the_transaction_is_funded_successfully() { var dataFolder = AssureEmptyDirAsDataFolder("TestData/WalletTransactionHandlerTest/FundTransaction_Given__a_wallet_has_enough_inputs__When__adding_inputs_to_an_existing_transaction__Then__the_transaction_is_funded_successfully"); var wallet = WalletTestsHelpers.GenerateBlankWallet("myWallet1", "password"); var accountKeys = WalletTestsHelpers.GenerateAccountKeys(wallet, "password", "m/44'/0'/0'"); var spendingKeys = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "0/0"); var destinationKeys1 = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "0/1"); var destinationKeys2 = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "0/2"); var destinationKeys3 = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "0/3"); var address = new HdAddress() { Index = 0, BlocksScanned = new SortedList <int, int>(), HdPath = $"m/44'/0'/0'/0/0", Address = spendingKeys.Address.ToString(), Pubkey = spendingKeys.PubKey.ScriptPubKey, ScriptPubKey = spendingKeys.Address.ScriptPubKey, Transactions = new List <TransactionData>() }; // wallet with 4 coinbase outputs of 50 = 200 Bitcoin var chain = new ConcurrentChain(wallet.Network.GetGenesis().Header); WalletTestsHelpers.AddBlocksWithCoinbaseToChain(wallet.Network, chain, address, 4); wallet.AccountsRoot.ElementAt(0).Accounts.Add(new HdAccount() { Index = 0, Name = "account1", HdPath = "m/44'/0'/0'", ExtendedPubKey = accountKeys.ExtPubKey, ExternalAddresses = new List <HdAddress>() { address }, InternalAddresses = new List <HdAddress>() { // no change addresses at the moment! } }); var walletFeePolicy = new Mock <IWalletFeePolicy>(); walletFeePolicy.Setup(w => w.GetFeeRate(FeeType.Low.ToConfirmations())).Returns(new FeeRate(20000)); var overrideFeeRate = new FeeRate(20000); var walletManager = new WalletManager(this.LoggerFactory.Object, It.IsAny <ConnectionManager>(), Network.Main, chain, NodeSettings.Default(), dataFolder, walletFeePolicy.Object, new Mock <IAsyncLoopFactory>().Object, new NodeLifetime()); var walletTransactionHandler = new WalletTransactionHandler(this.LoggerFactory.Object, chain, walletManager, walletFeePolicy.Object, Network.Main); walletManager.Wallets.Add(wallet); var walletReference = new WalletAccountReference() { AccountName = "account1", WalletName = "myWallet1" }; // create a trx with 3 outputs 50 + 50 + 49 = 149 BTC var context = new TransactionBuildContext(walletReference, new[] { new Recipient { Amount = new Money(50, MoneyUnit.BTC), ScriptPubKey = destinationKeys1.PubKey.ScriptPubKey }, new Recipient { Amount = new Money(50, MoneyUnit.BTC), ScriptPubKey = destinationKeys2.PubKey.ScriptPubKey }, new Recipient { Amount = new Money(49, MoneyUnit.BTC), ScriptPubKey = destinationKeys3.PubKey.ScriptPubKey } } .ToList(), "password") { MinConfirmations = 0, FeeType = FeeType.Low }; var fundTransaction = walletTransactionHandler.BuildTransaction(context); Assert.Equal(3, fundTransaction.Inputs.Count); // 3 inputs Assert.Equal(4, fundTransaction.Outputs.Count); // 3 outputs with change // remove the change output fundTransaction.Outputs.Remove(fundTransaction.Outputs.First(f => f.ScriptPubKey == context.ChangeAddress.ScriptPubKey)); // remove 2 inputs they will be added back by fund transaction fundTransaction.Inputs.RemoveAt(2); fundTransaction.Inputs.RemoveAt(1); Assert.Equal(1, fundTransaction.Inputs.Count); // 3 inputs var fundTransactionClone = fundTransaction.Clone(); var fundContext = new TransactionBuildContext(walletReference, new List <Recipient>(), "password") { MinConfirmations = 0, FeeType = FeeType.Low }; fundContext.OverrideFeeRate = overrideFeeRate; walletTransactionHandler.FundTransaction(fundContext, fundTransaction); foreach (var input in fundTransactionClone.Inputs) // all original inputs are still in the trx { Assert.True(fundTransaction.Inputs.Any(a => a.PrevOut == input.PrevOut)); } Assert.Equal(3, fundTransaction.Inputs.Count); // we expect 3 inputs Assert.Equal(4, fundTransaction.Outputs.Count); // we expect 4 outputs Assert.Equal(new Money(150, MoneyUnit.BTC) - fundContext.TransactionFee, fundTransaction.TotalOut); Assert.True(fundTransaction.Outputs.Any(a => a.ScriptPubKey == destinationKeys1.PubKey.ScriptPubKey)); Assert.True(fundTransaction.Outputs.Any(a => a.ScriptPubKey == destinationKeys2.PubKey.ScriptPubKey)); Assert.True(fundTransaction.Outputs.Any(a => a.ScriptPubKey == destinationKeys3.PubKey.ScriptPubKey)); }
public void BuildTransactionNoChangeAdressesLeftCreatesNewChangeAddress() { var dataFolder = AssureEmptyDirAsDataFolder("TestData/WalletTransactionHandlerTest/BuildTransactionNoChangeAdressesLeftCreatesNewChangeAddress"); var wallet = WalletTestsHelpers.GenerateBlankWallet("myWallet1", "password"); var accountKeys = WalletTestsHelpers.GenerateAccountKeys(wallet, "password", "m/44'/0'/0'"); var spendingKeys = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "0/0"); var destinationKeys = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "0/1"); var address = new HdAddress() { Index = 0, BlocksScanned = new SortedList <int, int>(), HdPath = $"m/44'/0'/0'/0/0", Address = spendingKeys.Address.ToString(), Pubkey = spendingKeys.PubKey.ScriptPubKey, ScriptPubKey = spendingKeys.Address.ScriptPubKey, Transactions = new List <TransactionData>() }; var chain = new ConcurrentChain(wallet.Network.GetGenesis().Header); WalletTestsHelpers.AddBlocksWithCoinbaseToChain(wallet.Network, chain, address); var addressTransaction = address.Transactions.First(); wallet.AccountsRoot.ElementAt(0).Accounts.Add(new HdAccount() { Index = 0, Name = "account1", HdPath = "m/44'/0'/0'", ExtendedPubKey = accountKeys.ExtPubKey, ExternalAddresses = new List <HdAddress>() { address }, InternalAddresses = new List <HdAddress>() { // no change addresses at the moment! } }); var walletFeePolicy = new Mock <IWalletFeePolicy>(); walletFeePolicy.Setup(w => w.GetFeeRate(FeeType.Low.ToConfirmations())) .Returns(new FeeRate(20000)); var walletManager = new WalletManager(this.LoggerFactory.Object, It.IsAny <ConnectionManager>(), Network.Main, chain, NodeSettings.Default(), dataFolder, walletFeePolicy.Object, new Mock <IAsyncLoopFactory>().Object, new NodeLifetime()); var walletTransactionHandler = new WalletTransactionHandler(this.LoggerFactory.Object, chain, walletManager, walletFeePolicy.Object, Network.Main); walletManager.Wallets.Add(wallet); var walletReference = new WalletAccountReference() { AccountName = "account1", WalletName = "myWallet1" }; var context = CreateContext(walletReference, "password", destinationKeys.PubKey.ScriptPubKey, new Money(7500), FeeType.Low, 0); var transactionResult = walletTransactionHandler.BuildTransaction(context); var result = new Transaction(transactionResult.ToHex()); var expectedChangeAddressKeys = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "1/0"); Assert.Equal(1, result.Inputs.Count); Assert.Equal(addressTransaction.Id, result.Inputs[0].PrevOut.Hash); Assert.Equal(2, result.Outputs.Count); var output = result.Outputs[0]; Assert.Equal((addressTransaction.Amount - context.TransactionFee - 7500), output.Value); Assert.Equal(expectedChangeAddressKeys.Address.ScriptPubKey, output.ScriptPubKey); output = result.Outputs[1]; Assert.Equal(7500, output.Value); Assert.Equal(destinationKeys.PubKey.ScriptPubKey, output.ScriptPubKey); Assert.Equal(addressTransaction.Amount - context.TransactionFee, result.TotalOut); Assert.NotNull(transactionResult.GetHash()); Assert.Equal(result.GetHash(), transactionResult.GetHash()); }
public void EstimateFeeWithLowFeeMatchesBuildTxLowFee() { var dataFolder = CreateDataFolder(this); Wallet wallet = WalletTestsHelpers.GenerateBlankWallet("myWallet1", "password"); var accountKeys = WalletTestsHelpers.GenerateAccountKeys(wallet, "password", "m/44'/0'/0'"); var spendingKeys = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "0/0"); var destinationKeys = WalletTestsHelpers.GenerateAddressKeys(wallet, accountKeys.ExtPubKey, "0/1"); HdAddress address = new HdAddress { Index = 0, HdPath = $"m/44'/0'/0'/0/0", Address = spendingKeys.Address.ToString(), Pubkey = spendingKeys.PubKey.ScriptPubKey, ScriptPubKey = spendingKeys.Address.ScriptPubKey, Transactions = new List <TransactionData>() }; ConcurrentChain chain = new ConcurrentChain(wallet.Network); WalletTestsHelpers.AddBlocksWithCoinbaseToChain(wallet.Network, chain, address); TransactionData addressTransaction = address.Transactions.First(); wallet.AccountsRoot.ElementAt(0).Accounts.Add(new HdAccount { Index = 0, Name = "account1", HdPath = "m/44'/0'/0'", ExtendedPubKey = accountKeys.ExtPubKey, ExternalAddresses = new List <HdAddress> { address }, InternalAddresses = new List <HdAddress>() }); var walletFeePolicy = new Mock <IWalletFeePolicy>(); walletFeePolicy.Setup(w => w.GetFeeRate(FeeType.Low.ToConfirmations())) .Returns(new FeeRate(20000)); var walletManager = new WalletManager(this.LoggerFactory.Object, Network.Main, chain, NodeSettings.Default(), dataFolder, walletFeePolicy.Object, new Mock <IAsyncLoopFactory>().Object, new NodeLifetime(), DateTimeProvider.Default); WalletTransactionHandler walletTransactionHandler = new WalletTransactionHandler(this.LoggerFactory.Object, chain, walletManager, walletFeePolicy.Object, Network.Main); walletManager.Wallets.Add(wallet); WalletAccountReference walletReference = new WalletAccountReference { AccountName = "account1", WalletName = "myWallet1" }; // Context to build requires password in order to sign transaction. TransactionBuildContext buildContext = CreateContext(walletReference, "password", destinationKeys.PubKey.ScriptPubKey, new Money(7500), FeeType.Low, 0); walletTransactionHandler.BuildTransaction(buildContext); // Context for estimate does not need password. TransactionBuildContext estimateContext = CreateContext(walletReference, null, destinationKeys.PubKey.ScriptPubKey, new Money(7500), FeeType.Low, 0); Money fee = walletTransactionHandler.EstimateFee(estimateContext); Assert.Equal(fee, buildContext.TransactionFee); }
private WalletTransactionHandlerTestContext SetupWallet(FeeRate feeRate = null, int coinBaseBlocks = 1) { DataFolder dataFolder = CreateDataFolder(this); IWalletRepository walletRepository = new SQLiteWalletRepository(this.LoggerFactory.Object, dataFolder, this.Network, DateTimeProvider.Default, new ScriptAddressReader()) { TestMode = true }; var walletFeePolicy = new Mock <IWalletFeePolicy>(); walletFeePolicy.Setup(w => w.GetFeeRate(FeeType.Low.ToConfirmations())) .Returns(feeRate ?? new FeeRate(20000)); var chain = new ChainIndexer(this.Network); var walletManager = new WalletManager(this.LoggerFactory.Object, this.Network, chain, new WalletSettings(NodeSettings.Default(this.Network)), dataFolder, walletFeePolicy.Object, new Mock <IAsyncProvider>().Object, new NodeLifetime(), DateTimeProvider.Default, this.scriptAddressReader, walletRepository); var reserveUtxoService = new ReserveUtxoService(this.loggerFactory, new Mock <ISignals>().Object); var walletTransactionHandler = new WalletTransactionHandler(this.LoggerFactory.Object, walletManager, walletFeePolicy.Object, this.Network, this.standardTransactionPolicy, reserveUtxoService); walletManager.Start(); var walletReference = new WalletAccountReference { AccountName = "account1", WalletName = "myWallet1" }; Wallet wallet = WalletTestsHelpers.GenerateBlankWallet(walletReference.WalletName, "password", walletRepository); (ExtKey ExtKey, string ExtPubKey)accountKeys = WalletTestsHelpers.GenerateAccountKeys(wallet, "password", $"m/44'/{this.Network.Consensus.CoinType}'/0'"); var account = wallet.AddNewAccount(accountKeys.ExtKey.Neuter(), accountName: walletReference.AccountName); var destinationAddress = account.ExternalAddresses.Skip(1).First(); (PubKey PubKey, BitcoinPubKeyAddress Address)destinationKeys = (destinationAddress.Pubkey.GetDestinationPublicKeys(this.Network).First(), new BitcoinPubKeyAddress(destinationAddress.Address, this.Network)); HdAddress address = account.ExternalAddresses.ElementAt(0); TransactionData addressTransaction = null; if (coinBaseBlocks != 0) { WalletTestsHelpers.AddBlocksWithCoinbaseToChain(wallet.Network, chain, address, coinBaseBlocks); addressTransaction = address.Transactions.First(); } return(new WalletTransactionHandlerTestContext { Wallet = wallet, AccountKeys = accountKeys, DestinationKeys = destinationKeys, AddressTransaction = addressTransaction, WalletTransactionHandler = walletTransactionHandler, WalletReference = walletReference }); }
public void When_BuildTransactionIsCalledWithoutTransactionFee_Then_MultipleSubtractFeeRecipients_ThrowsException() { DataFolder dataFolder = CreateDataFolder(this); IWalletRepository walletRepository = new SQLiteWalletRepository(this.LoggerFactory.Object, dataFolder, this.Network, DateTimeProvider.Default, new ScriptAddressReader()) { TestMode = true }; var walletFeePolicy = new Mock <IWalletFeePolicy>(); walletFeePolicy.Setup(w => w.GetFeeRate(FeeType.Low.ToConfirmations())).Returns(new FeeRate(20000)); var walletManager = new WalletManager(this.LoggerFactory.Object, this.Network, new ChainIndexer(this.Network), new WalletSettings(NodeSettings.Default(this.Network)), dataFolder, walletFeePolicy.Object, new Mock <IAsyncProvider>().Object, new NodeLifetime(), DateTimeProvider.Default, this.scriptAddressReader, walletRepository); walletManager.Start(); var reserveUtxoService = new ReserveUtxoService(this.loggerFactory, new Mock <ISignals>().Object); var walletTransactionHandler = new WalletTransactionHandler(this.LoggerFactory.Object, walletManager, walletFeePolicy.Object, this.Network, this.standardTransactionPolicy, reserveUtxoService); (Wallet wallet, ExtKey extKey) = WalletTestsHelpers.GenerateBlankWalletWithExtKey("myWallet1", "password", walletRepository); walletManager.Wallets.Add(wallet); int accountIndex = 0; ExtKey addressExtKey = extKey.Derive(new KeyPath($"m/44'/{this.Network.Consensus.CoinType}'/{accountIndex}'")); ExtPubKey extPubKey = addressExtKey.Neuter(); HdAccount account = wallet.AddNewAccount(extPubKey, accountName: "account1"); var address = account.ExternalAddresses.First(); var destination = account.InternalAddresses.First(); var destination2 = account.InternalAddresses.Skip(1).First(); var destination3 = account.InternalAddresses.Skip(2).First(); // Wallet with 4 coinbase outputs of 50 = 200. var chain = new ChainIndexer(wallet.Network); WalletTestsHelpers.AddBlocksWithCoinbaseToChain(wallet.Network, chain, address, 4); var walletReference = new WalletAccountReference { AccountName = "account1", WalletName = "myWallet1" }; // Create a transaction with 3 outputs 50 + 50 + 50 = 150 but with fees charged to recipients. var context = new TransactionBuildContext(this.Network) { AccountReference = walletReference, MinConfirmations = 0, FeeType = FeeType.Low, WalletPassword = "******", Recipients = new[] { new Recipient { Amount = new Money(50, MoneyUnit.BTC), ScriptPubKey = destination.ScriptPubKey, SubtractFeeFromAmount = true }, new Recipient { Amount = new Money(50, MoneyUnit.BTC), ScriptPubKey = destination2.ScriptPubKey, SubtractFeeFromAmount = true }, new Recipient { Amount = new Money(50, MoneyUnit.BTC), ScriptPubKey = destination3.ScriptPubKey, SubtractFeeFromAmount = false } }.ToList() }; Assert.Throws <WalletException>(() => walletTransactionHandler.BuildTransaction(context)); }