Ejemplo n.º 1
0
        public void SendTest(
            BitcoinBasedConfig currency,
            decimal available,
            decimal amount,
            decimal fee,
            DustUsagePolicy dustUsagePolicy)
        {
            var error = Send(
                currency: currency,
                available: available,
                amount: amount,
                fee: fee,
                dustUsagePolicy: dustUsagePolicy,
                apiSetup: apiMock =>
            {
                apiMock.Setup(a => a.TryBroadcastAsync(It.IsAny <IBlockchainTransaction>(), 3, 1000, CancellationToken.None))
                .Returns(Task.FromResult(new Result <string>("<txid>")));
            },
                repositorySetup: (repositoryMock, fromAddress) =>
            {
                repositoryMock.Setup(r => r.GetWalletAddressAsync(It.IsAny <string>(), fromAddress.Address))
                .Returns(Task.FromResult(fromAddress));
            });

            Assert.Null(error);
        }
Ejemplo n.º 2
0
        public void SendDustAsFeeTest(
            BitcoinBasedConfig currency,
            decimal available,
            decimal amount,
            decimal fee,
            DustUsagePolicy dustUsagePolicy)
        {
            var change = available - amount - fee;

            var broadcastCallback = new Action <IBlockchainTransaction, int, int, CancellationToken>((tx, attempts, attemptsInterval, token) =>
            {
                var btcBasedTx = (IBitcoinBasedTransaction)tx;
                Assert.True(btcBasedTx.Fees == currency.CoinToSatoshi(fee + change));
            });

            var error = Send(
                currency: currency,
                available: available,
                amount: amount,
                fee: fee,
                dustUsagePolicy: dustUsagePolicy,
                apiSetup: apiMock =>
            {
                apiMock.Setup(a => a.TryBroadcastAsync(It.IsAny <IBlockchainTransaction>(), 3, 1000, CancellationToken.None))
                .Callback(broadcastCallback)
                .Returns(Task.FromResult(new Result <string>("<txid>")));
            },
                repositorySetup: (repositoryMock, fromAddress) =>
            {
                repositoryMock.Setup(r => r.GetWalletAddressAsync(It.IsAny <string>(), fromAddress.Address))
                .Returns(Task.FromResult(fromAddress));
            });

            Assert.Null(error);
        }
Ejemplo n.º 3
0
        public void SpentSegwitPaymentTx(BitcoinBasedConfig currency)
        {
            const int paymentQty = 1_0000_0000;

            var paymentTx        = SignSegwitPaymentTx(currency);
            var paymentTxOutputs = paymentTx.Outputs
                                   .Where(o => o.Value == paymentQty)
                                   .ToArray();

            var spentTx = currency.CreateP2WPkhTx(
                unspentOutputs: paymentTxOutputs,
                destinationAddress: Common.Bob
                .PubKey
                .GetSegwitAddress(currency.Network)
                .ToString(),
                changeAddress: Common.Bob
                .PubKey
                .GetSegwitAddress(currency.Network)
                .ToString(),
                amount: 9999_0000,
                fee: 1_0000);

            spentTx.Sign(Common.Bob, paymentTxOutputs, currency);

            Assert.True(spentTx.Verify(paymentTxOutputs, currency));
        }
Ejemplo n.º 4
0
        public IBitcoinBasedTransaction CreateSegwitPaymentTx(BitcoinBasedConfig currency)
        {
            var       initTx = BitcoinBasedCommon.CreateFakeTx(currency, Common.Alice.PubKey, 1_0000_0000, 1_0000_0000);
            const int amount = 1_0000_0000;
            const int fee    = 1_0000;
            const int change = 9999_0000;

            var tx = BitcoinBasedCommon.CreateSegwitPaymentTx(
                currency: currency,
                outputs: initTx.Outputs,
                from: Common.Alice.PubKey,
                to: Common.Bob.PubKey,
                amount: amount,
                fee: fee);

            Assert.NotNull(tx);
            Assert.True(tx.Check());
            Assert.NotNull(tx.Outputs.FirstOrDefault(o => o.Value == amount));
            Assert.NotNull(tx.Outputs.FirstOrDefault(o => o.Value == change));
            Assert.Equal(tx.Outputs.First(o => o.Value == amount).DestinationAddress(currency.Network), Common.BobSegwitAddress(currency));
            Assert.Equal(initTx.TotalOut - fee, tx.TotalOut);
            Assert.Equal(fee, tx.GetFee(initTx.Outputs));

            return(tx);
        }
Ejemplo n.º 5
0
        public IBitcoinBasedTransaction CreatePaymentTx(BitcoinBasedConfig currency)
        {
            var       initTx = BitcoinBasedCommon.CreateFakeTx(currency, Common.Alice.PubKey, 1_0000_0000, 1_0000_0000);
            const int amount = 1_0000_0000;
            const int fee    = 1_0000;
            const int change = 9999_0000;

            var tx = currency.CreatePaymentTx(
                unspentOutputs: initTx.Outputs,
                destinationAddress: Common.Bob.PubKey.GetAddress(currency),
                changeAddress: Common.Alice.PubKey.GetAddress(currency),
                amount: amount,
                fee: fee,
                lockTime: DateTimeOffset.MinValue);

            Assert.NotNull(tx);
            Assert.True(tx.Check());
            Assert.NotNull(tx.Outputs.FirstOrDefault(o => o.Value == amount));
            Assert.NotNull(tx.Outputs.FirstOrDefault(o => o.Value == change));
            Assert.Equal(tx.Outputs.First(o => o.Value == amount).DestinationAddress(currency.Network), Common.BobAddress(currency));
            Assert.Equal(tx.Outputs.First(o => o.Value == change).DestinationAddress(currency.Network), Common.AliceAddress(currency));
            Assert.Equal(initTx.TotalOut - fee, tx.TotalOut);
            Assert.Equal(fee, tx.GetFee(initTx.Outputs));

            return(tx);
        }
Ejemplo n.º 6
0
        public static BitcoinBasedTransaction CreateTransaction(
            BitcoinBasedConfig currency,
            IEnumerable <ICoin> coins,
            Script destination,
            Script change,
            long amount,
            long fee,
            DateTimeOffset lockTime,
            params Script[] knownRedeems)
        {
            var tx = currency.Network.CreateTransactionBuilder()
                     .SetDustPrevention(false)
                     .SetOptInRBF(true)
                     .AddCoins(coins)
                     .Send(destination, new Money(amount))
                     .SendFees(new Money(fee))
                     .SetChange(change)
                     .SetLockTime(lockTime != DateTimeOffset.MinValue
                    ? new LockTime(lockTime)
                    : NBitcoin.LockTime.Zero)
                     .AddKnownRedeems(knownRedeems)
                     .BuildTransaction(false);

            return(new BitcoinBasedTransaction(
                       currency: currency.Name,
                       tx: tx,
                       blockInfo: null,
                       fees: (long)tx.GetFee(coins.ToArray()).ToUnit(MoneyUnit.Satoshi)));
        }
Ejemplo n.º 7
0
        public (IBitcoinBasedTransaction, byte[]) CreateHtlcP2PkhScriptSwapPaymentTx(BitcoinBasedConfig currency)
        {
            var       initTx = BitcoinBasedCommon.CreateFakeTx(currency, Common.Alice.PubKey, 1_0000_0000, 1_0000_0000);
            const int amount = 1_0000_0000;
            const int fee    = 1_0000;
            //const int change = 9999_0000;

            var tx = currency.CreateHtlcP2PkhScriptSwapPaymentTx(
                unspentOutputs: initTx.Outputs,
                aliceRefundAddress: Common.Alice.PubKey.GetAddress(currency),
                bobAddress: Common.Bob.PubKey.GetAddress(currency),
                lockTime: DateTimeOffset.UtcNow.AddHours(1),
                secretHash: Common.SecretHash,
                secretSize: Common.Secret.Length,
                amount: amount,
                fee: fee,
                redeemScript: out var redeemScript);

            Assert.NotNull(tx);
            Assert.NotNull(redeemScript);
            Assert.True(tx.Check());
            Assert.Equal(initTx.TotalOut - fee, tx.TotalOut);
            Assert.Equal(fee, tx.GetFee(initTx.Outputs));

            return(tx, redeemScript);
        }
Ejemplo n.º 8
0
        public static ICurrencySwap Create(
            CurrencyConfig currency,
            IAccount account)
        {
            return(currency switch
            {
                BitcoinBasedConfig _ => new BitcoinBasedSwap(
                    account: account.GetCurrencyAccount <BitcoinBasedAccount>(currency.Name),
                    currencies: account.Currencies),

                Erc20Config _ => new Erc20Swap(
                    account: account.GetCurrencyAccount <Erc20Account>(currency.Name),
                    ethereumAccount: account.GetCurrencyAccount <EthereumAccount>("ETH"),
                    currencies: account.Currencies),

                EthereumConfig _ => new EthereumSwap(
                    account: account.GetCurrencyAccount <EthereumAccount>(currency.Name),
                    currencies: account.Currencies),

                Fa12Config _ => new Fa12Swap(
                    account: account.GetCurrencyAccount <Fa12Account>(currency.Name),
                    tezosAccount: account.GetCurrencyAccount <TezosAccount>(TezosConfig.Xtz),
                    currencies: account.Currencies),

                TezosConfig _ => new TezosSwap(
                    account:   account.GetCurrencyAccount <TezosAccount>(currency.Name),
                    currencies: account.Currencies),

                _ => throw new NotSupportedException($"Not supported currency {currency.Name}")
            });
Ejemplo n.º 9
0
        public async void GetBalanceTest(
            BitcoinBasedConfig currency,
            string address)
        {
            var api           = new BlockCypherApi(currency, BlockCypherApi.BitcoinMainNet);
            var balanceResult = await api.GetBalanceAsync(address);

            Assert.False(balanceResult.HasError, balanceResult.Error?.Description ?? "");
        }
Ejemplo n.º 10
0
        public void Sign(
            SecureBytes privateKey,
            ITxOutput[] spentOutputs,
            BitcoinBasedConfig bitcoinBasedConfig)
        {
            using var scopedPrivateKey = privateKey.ToUnsecuredBytes();

            Sign(new Key(scopedPrivateKey), spentOutputs, bitcoinBasedConfig); // todo: do not use NBitcoin.Key
        }
        public async Task <IBitcoinBasedTransaction> CreateSwapRefundTxAsync(
            IBitcoinBasedTransaction paymentTx,
            long amount,
            string refundAddress,
            byte[] redeemScript,
            DateTimeOffset lockTime,
            BitcoinBasedConfig currencyConfig)
        {
            var swapOutput = paymentTx.Outputs
                             .Cast <BitcoinBasedTxOutput>()
                             .FirstOrDefault(o => o.IsPayToScriptHash(redeemScript));

            if (swapOutput == null)
            {
                throw new Exception("Can't find pay to script hash output");
            }

            var feeRate = await currencyConfig
                          .GetFeeRateAsync()
                          .ConfigureAwait(false);

            var inputSize = new BitcoinInputToSign
            {
                Output = swapOutput,
                Signer = new BitcoinRefundSigner()
            }.SizeWithSignature();

            var outputSize = new BitcoinDestination
            {
                AmountInSatoshi = amount,
                Script          = BitcoinAddress.Create(refundAddress, currencyConfig.Network).ScriptPubKey
            }.Size();

            var(txSize, _) = BitcoinTransactionParams.CalculateTxSize(
                inputsCount: 1,
                inputsSize: inputSize,
                outputsCount: 1,
                outputsSize: outputSize,
                witnessCount: swapOutput.IsSegWit ? 1 : 0,
                changeOutputSize: 0);

            var feeInSatoshi = (long)(txSize * feeRate);

            if (amount - feeInSatoshi < 0)
            {
                throw new Exception($"Insufficient funds for fee. Available {amount}, required {feeInSatoshi}");
            }

            return(currencyConfig.CreateP2PkhTx(
                       unspentOutputs: new ITxOutput[] { swapOutput },
                       destinationAddress: refundAddress,
                       changeAddress: refundAddress,
                       amount: amount - feeInSatoshi,
                       fee: feeInSatoshi,
                       lockTime: lockTime,
                       knownRedeems: new Script(redeemScript)));
        }
Ejemplo n.º 12
0
        public void Sign(
            Key privateKey,
            ITxOutput spentOutput,
            BitcoinBasedConfig bitcoinBasedConfig)
        {
            var output = (BitcoinBasedTxOutput)spentOutput;

            Tx.Sign(new BitcoinSecret(privateKey, bitcoinBasedConfig.Network), output.Coin);
        }
Ejemplo n.º 13
0
 public BitcoinBasedTransactionViewModel(
     IBitcoinBasedTransaction tx,
     BitcoinBasedConfig bitcoinBasedConfig)
     : base(tx, bitcoinBasedConfig, tx.Amount / bitcoinBasedConfig.DigitsMultiplier, GetFee(tx, bitcoinBasedConfig))
 {
     Fee = tx.Fees != null
         ? tx.Fees.Value / bitcoinBasedConfig.DigitsMultiplier
         : 0; // todo: N/A
 }
        public static IBitcoinBasedTransaction CreateFakeTx(BitcoinBasedConfig currency, PubKey to, params long[] outputs)
        {
            var tx = Transaction.Create(currency.Network);

            foreach (var output in outputs)
            {
                tx.Outputs.Add(new TxOut(new Money(output), to.Hash)); // p2pkh
            }
            return(new BitcoinBasedTransaction(currency.Name, tx));
        }
Ejemplo n.º 15
0
        public byte[] SignMessageByServiceKey(byte[] data, int chain, uint index)
        {
            using var masterKey = BitcoinBasedConfig
                                  .CreateExtKeyFromSeed(Seed);

            using var derivedKey = masterKey
                                   .Derive(new KeyPath(path: $"m/{ServicePurpose}'/0'/0'/{chain}/{index}"));

            return(derivedKey.SignMessage(data));
        }
Ejemplo n.º 16
0
 public void Sign(
     Key privateKey,
     ITxOutput[] spentOutputs,
     BitcoinBasedConfig bitcoinBasedConfig)
 {
     foreach (var output in spentOutputs)
     {
         Sign(privateKey, output, bitcoinBasedConfig);
     }
 }
Ejemplo n.º 17
0
        public SecureBytes GetServicePublicKey(uint index)
        {
            using var masterKey = BitcoinBasedConfig
                                  .CreateExtKeyFromSeed(Seed);

            using var extKey = masterKey
                               .Derive(new KeyPath(path: $"m/{ServicePurpose}'/0'/0'/0/{index}"));

            return(extKey.GetPublicKey());
        }
Ejemplo n.º 18
0
 private static decimal GetFee(
     IBitcoinBasedTransaction tx,
     BitcoinBasedConfig bitcoinBasedConfig)
 {
     return(tx.Fees != null
         ? tx.Type.HasFlag(BlockchainTransactionType.Output)
             ? tx.Fees.Value / bitcoinBasedConfig.DigitsMultiplier
             : 0
         : 0);
 }
Ejemplo n.º 19
0
 public static SendViewModel CreateViewModel(IAtomexApp app, CurrencyViewModel currencyViewModel)
 {
     return(currencyViewModel.Currency switch
     {
         BitcoinBasedConfig _ => (SendViewModel) new BitcoinBasedSendViewModel(app, currencyViewModel),
         Erc20Config _ => (SendViewModel) new Erc20SendViewModel(app, currencyViewModel),
         EthereumConfig _ => (SendViewModel) new EthereumSendViewModel(app, currencyViewModel),
         Fa12Config _ => (SendViewModel) new Fa12SendViewModel(app, currencyViewModel),
         TezosConfig _ => (SendViewModel) new TezosSendViewModel(app, currencyViewModel),
         _ => throw new NotSupportedException($"Can't create send view model for {currencyViewModel.Currency.Name}. This currency is not supported."),
     });
Ejemplo n.º 20
0
        public void ExtractSecretFromHtlcP2PkhScriptSwapRedeemTx(BitcoinBasedConfig currency)
        {
            var tx = SignHtlcP2PkhScriptSwapRedeemTx(currency);

            var data = (tx.Inputs.First() as BitcoinBasedTxPoint)
                       .ExtractAllPushData();

            var secret = data.FirstOrDefault(d => d.SequenceEqual(Common.Secret));

            Assert.NotNull(secret);
        }
Ejemplo n.º 21
0
        public IBitcoinBasedTransaction SignSegwitPaymentTx(BitcoinBasedConfig currency)
        {
            var initTx = BitcoinBasedCommon.CreateFakeTx(currency, Common.Alice.PubKey, 1_0000_0000, 1_0000_0000);
            var tx     = CreateSegwitPaymentTx(currency);

            tx.Sign(Common.Alice, initTx.Outputs, currency);

            Assert.True(tx.Verify(initTx.Outputs, currency));

            return(tx);
        }
Ejemplo n.º 22
0
        public (IBitcoinBasedTransaction, byte[]) SignHtlcP2PkhScriptSwapPaymentTx(BitcoinBasedConfig currency)
        {
            var initTx = BitcoinBasedCommon.CreateFakeTx(currency, Common.Alice.PubKey, 1_0000_0000, 1_0000_0000);

            var(tx, redeemScript) = CreateHtlcP2PkhScriptSwapPaymentTx(currency);

            tx.Sign(Common.Alice, initTx.Outputs, currency);

            Assert.True(tx.Verify(initTx.Outputs, currency));

            return(tx, redeemScript);
        }
Ejemplo n.º 23
0
        public async void GetUnspentOutputsTest(
            BitcoinBasedConfig currency,
            string address)
        {
            var api        = new BlockCypherApi(currency, BlockCypherApi.BitcoinMainNet);
            var utxoResult = await api.GetUnspentOutputsAsync(address);

            Assert.False(utxoResult.HasError, utxoResult.Error?.Description ?? "");

            var utxo = utxoResult.Value;

            Assert.NotNull(utxo);
        }
 public static IBitcoinBasedTransaction CreateSegwitPaymentTx(
     BitcoinBasedConfig currency,
     IEnumerable <ITxOutput> outputs,
     PubKey from,
     PubKey to,
     int amount,
     int fee)
 {
     return(currency.CreateP2WPkhTx(
                unspentOutputs: outputs,
                destinationAddress: to.GetSegwitAddress(currency.Network).ToString(),
                changeAddress: from.GetSegwitAddress(currency.Network).ToString(),
                amount: amount,
                fee: fee));
 }
Ejemplo n.º 25
0
        public bool Verify(
            ITxOutput spentOutput,
            BitcoinBasedConfig bitcoinBasedConfig,
            bool checkScriptPubKey = true)
        {
            var result = bitcoinBasedConfig.Network.CreateTransactionBuilder()
                         .SetTransactionPolicy(new StandardTransactionPolicy
            {
                CheckScriptPubKey = checkScriptPubKey,
                ScriptVerify      = ScriptVerify.Standard
            })
                         .AddCoins(((BitcoinBasedTxOutput)spentOutput).Coin)
                         .Verify(Tx, out _);

            return(result);
        }
 public static Task <BitcoinTransactionParams> SelectTransactionParamsByFeeRateAsync(
     IEnumerable <BitcoinInputToSign> availableInputs,
     IEnumerable <BitcoinDestination> destinations,
     string changeAddress,
     decimal feeRate,
     BitcoinBasedConfig currencyConfig,
     CancellationToken cancellationToken = default)
 {
     return(SelectTransactionParamsByFeeRateAsync(
                availableInputs: availableInputs,
                destinations: destinations.Select(d => (d.AmountInSatoshi, d.Size())),
                changeAddress: changeAddress,
                feeRate: feeRate,
                currencyConfig: currencyConfig,
                cancellationToken: cancellationToken));
 }
Ejemplo n.º 27
0
        public void SendDustChangeFailTest(
            BitcoinBasedConfig currency,
            decimal available,
            decimal amount,
            decimal fee,
            DustUsagePolicy dustUsagePolicy)
        {
            var error = Send(
                currency: currency,
                available: available,
                amount: amount,
                fee: fee,
                dustUsagePolicy: dustUsagePolicy);

            Assert.NotNull(error);
            Assert.Equal(Errors.InsufficientAmount, error.Code);
        }
Ejemplo n.º 28
0
        private Error Send(
            BitcoinBasedConfig currency,
            decimal available,
            decimal amount,
            decimal fee,
            DustUsagePolicy dustUsagePolicy,
            Action <Mock <IBlockchainApi> > apiSetup = null,
            Action <Mock <IAccountDataRepository>, WalletAddress> repositorySetup = null)
        {
            var apiMock = new Mock <IBlockchainApi>();

            apiSetup?.Invoke(apiMock);

            var wallet      = new HdWallet(Network.TestNet);
            var fromAddress = wallet.GetAddress(
                currency: currency,
                account: 0,
                chain: 0,
                index: 0,
                keyType: CurrencyConfig.StandardKey);
            var fromOutputs = GetOutputs(fromAddress.Address, NBitcoin.Network.TestNet, currency.CoinToSatoshi(available)).ToList();

            var repositoryMock = new Mock <IAccountDataRepository>();

            repositorySetup?.Invoke(repositoryMock, fromAddress);

            var currencies = Common.CurrenciesTestNet;

            currencies.GetByName(currency.Name).BlockchainApi = apiMock.Object;

            var account = new BitcoinBasedAccount(
                currency: currency.Name,
                currencies: currencies,
                wallet: wallet,
                dataRepository: repositoryMock.Object);

            return(account
                   .SendAsync(
                       from: fromOutputs,
                       to: currency.TestAddress(),
                       amount: amount,
                       fee: fee,
                       dustUsagePolicy: dustUsagePolicy)
                   .WaitForResult());
        }
Ejemplo n.º 29
0
        public async void IsTransactionOutputSpentTest(
            BitcoinBasedConfig currency,
            string txId,
            uint outputNo,
            string spentTxId,
            uint spentIndex)
        {
            var api = new BlockCypherApi(currency, BlockCypherApi.BitcoinMainNet);
            var spentPointResult = await api.IsTransactionOutputSpent(txId, outputNo);

            Assert.False(spentPointResult.HasError, spentPointResult.Error?.Description ?? "");

            var spentPoint = spentPointResult.Value;

            Assert.NotNull(spentPoint);
            Assert.Equal(spentTxId, spentPoint.Hash);
            Assert.Equal(spentIndex, spentPoint.Index);
        }
Ejemplo n.º 30
0
        public async void GetInputTest(
            BitcoinBasedConfig currency,
            string txId,
            uint inputIndex,
            string prevTxId,
            uint prevTxOutputIndex)
        {
            var api         = new BlockCypherApi(currency, BlockCypherApi.BitcoinMainNet);
            var inputResult = await api.GetInputAsync(txId, inputIndex);

            Assert.False(inputResult.HasError, inputResult.Error?.Description ?? "");

            var input = inputResult.Value;

            Assert.NotNull(input);
            Assert.Equal(prevTxId, input.Hash);
            Assert.Equal(prevTxOutputIndex, input.Index);
        }