コード例 #1
0
        private async Task <IBitcoinBasedTransaction> GetPaymentTxAsync(
            BitcoinBasedCurrency currency,
            string txId)
        {
            var attempts = 0;

            while (attempts < DefaultGetTransactionAttempts)
            {
                attempts++;

                var tx = (IBitcoinBasedTransaction)await currency.BlockchainApi
                         .GetTransactionAsync(txId)
                         .ConfigureAwait(false);

                if (tx != null)
                {
                    return(tx);
                }

                await Task.Delay(DefaultGetTransactionInterval)
                .ConfigureAwait(false);
            }

            throw new InternalException(
                      code: Errors.SwapError,
                      description: $"Transaction with id {txId} not found");
        }
コード例 #2
0
        public IBitcoinBasedTransaction SignSwapRefundTxAlice2Bob(BitcoinBasedCurrency currency)
        {
            const int paymentQty = 3000;

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

            var       lockTime = DateTimeOffset.Now.AddHours(12);
            const int amount   = 2000;
            const int fee      = 1000;
            // change = 0;

            var refundTx = BitcoinBasedCommon.CreateSwapRefundTx(
                currency: Common.BtcTestNet,
                outputs: paymentTxOutputs,
                from: Common.Alice.PubKey,
                to: Common.Alice.PubKey,
                amount: amount,
                fee: fee,
                lockTime: lockTime
                );

            var sigHash = new uint256(refundTx.GetSignatureHash(paymentTxOutputs.First()));

            var aliceSign    = Common.Alice.Sign(sigHash, SigHash.All);
            var bobSign      = Common.Bob.Sign(sigHash, SigHash.All);
            var refundScript = BitcoinBasedSwapTemplate.GenerateSwapRefund(aliceSign, bobSign);

            refundTx.NonStandardSign(refundScript, paymentTxOutputs.First());

            Assert.True(refundTx.Verify(paymentTxOutputs));

            return(refundTx);
        }
コード例 #3
0
        public IBitcoinBasedTransaction CreateSwapRefundTxAlice2Bob(BitcoinBasedCurrency currency)
        {
            const int paymentQty = 3000;

            var paymentTx        = CreateP2PkSwapPaymentTxAlice2Bob(currency);
            var paymentTxOutputs = paymentTx.Outputs
                                   .Where(o => o.Value == paymentQty)
                                   .ToArray();
            var paymentTxTotal = paymentTxOutputs.Aggregate(0L, (s, output) => s + output.Value);

            var       lockTime = DateTimeOffset.Now.AddHours(12);
            const int amount   = 2000;
            const int fee      = 1000;
            // change = 0;

            var tx = BitcoinBasedCommon.CreateSwapRefundTx(
                currency: Common.BtcTestNet,
                outputs: paymentTxOutputs,
                from: Common.Alice.PubKey,
                to: Common.Alice.PubKey,
                amount: amount,
                fee: fee,
                lockTime: lockTime
                );

            Assert.True(tx.Check());
            Assert.Equal(paymentTxTotal - fee, tx.TotalOut);
            Assert.Equal(fee, tx.GetFee(paymentTxOutputs));

            return(tx);
        }
コード例 #4
0
        public static BitcoinBasedTransaction CreateTransaction(
            BitcoinBasedCurrency currency,
            IEnumerable <ICoin> coins,
            Script destination,
            Script change,
            long amount,
            long fee,
            DateTimeOffset lockTime)
        {
            var tx = currency.Network.CreateTransactionBuilder()
                     .SetDustPrevention(false)
                     .AddCoins(coins)
                     .Send(destination, new Money(amount))
                     .SendFees(new Money(fee))
                     .SetChange(change)
                     .SetLockTime(lockTime != DateTimeOffset.MinValue
                    ? new LockTime(lockTime)
                    : NBitcoin.LockTime.Zero)
                     .BuildTransaction(false);

            return(new BitcoinBasedTransaction(
                       currency: currency,
                       tx: tx,
                       blockInfo: null,
                       fees: (long)tx.GetFee(coins.ToArray()).ToUnit(MoneyUnit.Satoshi)));
        }
コード例 #5
0
        public async void GetTransactionTest(BitcoinBasedCurrency currency, string txId)
        {
            var api = new BlockchainInfoApi(currency);
            var tx  = await api.GetTransactionAsync(txId);

            Assert.NotNull(tx);
            Assert.True(tx.Id == txId);
        }
 private static WalletAddress GetWallet(BitcoinBasedCurrency currency, PubKey pubKey)
 {
     return(new WalletAddress
     {
         Address = pubKey.GetAddress(ScriptPubKeyType.Legacy, currency.Network).ToString(),
         Currency = currency,
         PublicKey = Convert.ToBase64String(pubKey.ToBytes())
     });
 }
コード例 #7
0
        public byte[] SignMessageByServiceKey(byte[] data, int chain, uint index)
        {
            using var masterKey = BitcoinBasedCurrency
                                  .CreateExtKeyFromSeed(Seed);

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

            return(derivedKey.SignMessage(data));
        }
コード例 #8
0
        public SecureBytes GetServicePublicKey(uint index)
        {
            using var masterKey = BitcoinBasedCurrency
                                  .CreateExtKeyFromSeed(Seed);

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

            return(extKey.GetPublicKey());
        }
コード例 #9
0
        public async void GetUnspentOutputsTest(
            BitcoinBasedCurrency currency,
            string baseUri,
            string address)
        {
            var api  = new InsightApi(currency, baseUri);
            var utxo = await api.GetUnspentOutputsAsync(address);

            Assert.NotNull(utxo);
        }
コード例 #10
0
        public byte[] GetServicePublicKey(uint index)
        {
            var extKey = BitcoinBasedCurrency
                         .CreateExtKeyFromSeed(Seed)
                         .Derive(new KeyPath(path: $"m/{ServicePurpose}'/0'/0'/0/{index}"));

            extKey.GetPublicKey(out var publicKey);

            return(publicKey);
        }
コード例 #11
0
        public async void GetBalanceTest(
            BitcoinBasedCurrency currency,
            string baseUri,
            string address)
        {
            var api           = new InsightApi(currency, baseUri);
            var balanceResult = await api.GetBalanceAsync(address);

            Assert.False(balanceResult.HasError, balanceResult.Error?.Description ?? "");
        }
コード例 #12
0
        public async void GetBalanceTest(
            BitcoinBasedCurrency currency,
            string baseUri,
            string address)
        {
            var api     = new InsightApi(currency, baseUri);
            var balance = await api.GetBalanceAsync(address);

            // todo: catch error
        }
コード例 #13
0
        public static IBitcoinBasedTransaction CreateFakeTx(BitcoinBasedCurrency 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, tx.ToBytes()));
        }
コード例 #14
0
        public IBitcoinBasedTransaction SignSegwitPaymentTx(BitcoinBasedCurrency 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);

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

            return(tx);
        }
コード例 #15
0
        public IBitcoinBasedTransaction SignHtlcP2PkhSwapPaymentTx(BitcoinBasedCurrency currency)
        {
            var initTx = BitcoinBasedCommon.CreateFakeTx(currency, Common.Alice.PubKey, 1_0000_0000, 1_0000_0000);
            var tx     = CreateHtlcP2PkhSwapPaymentTx(currency);

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

            Assert.True(tx.Verify(initTx.Outputs, checkScriptPubKey: false));

            return(tx);
        }
コード例 #16
0
        public IBitcoinBasedTransaction SignHtlcP2PkhSwapPaymentTxAlice2Bob(BitcoinBasedCurrency currency)
        {
            var initTx = CreateFakeTx(currency, Common.Alice.PubKey);
            var tx     = CreateHtlcP2PkhSwapPaymentTxAlice2Bob(currency);

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

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

            return(tx);
        }
コード例 #17
0
        public BlockchainInfoApi(BitcoinBasedCurrency currency)
        {
            _currency = currency ?? throw new ArgumentNullException(nameof(currency));

            var baseUrl = _currency.Network == Network.Main
                 ? "https://blockchain.info/"
                 : "https://testnet.blockchain.info/";

            _client   = new BlockchainHttpClient(apiCode: _apiCode, uri: baseUrl);
            _explorer = new BlockchainApiHelper(apiCode: _apiCode, baseHttpClient: new BlockchainHttpClient(uri: baseUrl)).blockExplorer;
        }
コード例 #18
0
        public void ExtractSecretFromHtlcP2PkhScriptSwapRedeemTx(BitcoinBasedCurrency 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);
        }
コード例 #19
0
 public bool VerifyMessageByServiceKey(
     byte[] data,
     byte[] signature,
     int chain,
     uint index)
 {
     return(BitcoinBasedCurrency
            .CreateExtKeyFromSeed(Seed)
            .Derive(new KeyPath(path: $"m/{ServicePurpose}'/0'/0'/{chain}/{index}"))
            .VerifyMessage(data, signature));
 }
コード例 #20
0
        public IBitcoinBasedTransaction CreateFakeTx(BitcoinBasedCurrency currency, PubKey destination)
        {
            const int output1 = 2000;
            const int output2 = 4000;

            var tx = BitcoinBasedCommon.CreateFakeTx(currency, destination, output1, output2);

            Assert.NotNull(tx);
            Assert.Equal(output1 + output2, tx.TotalOut);

            return(tx);
        }
コード例 #21
0
        public (IBitcoinBasedTransaction, byte[]) SignHtlcP2PkhScriptSwapPaymentTx(BitcoinBasedCurrency 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);

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

            return(tx, redeemScript);
        }
コード例 #22
0
        public SoChainApi(BitcoinBasedCurrency currency)
        {
            Currency = currency ?? throw new ArgumentNullException(nameof(currency));

            var networkAcronym = AcronymByNetwork(currency.Network);

            if (!Acronyms.ContainsValue(networkAcronym))
            {
                throw new NotSupportedException($"Network {networkAcronym} not supported by chain.so api!");
            }

            NetworkAcronym = networkAcronym;
        }
コード例 #23
0
        public Task <IBitcoinBasedTransaction> CreateSwapRedeemTxAsync(
            IBitcoinBasedTransaction paymentTx,
            long amount,
            string redeemAddress,
            byte[] redeemScript,
            uint sequenceNumber = 0)
        {
            var currency = (BitcoinBasedCurrency)paymentTx.Currency;

            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 estimatedSigSize = BitcoinBasedCurrency.EstimateSigSize(swapOutput, forRedeem: true);

            var tx = currency.CreateP2PkhTx(
                unspentOutputs: new ITxOutput[] { swapOutput },
                destinationAddress: redeemAddress,
                changeAddress: redeemAddress,
                amount: amount,
                fee: 0,
                lockTime: DateTimeOffset.MinValue);

            // fee = txSize * feeRate without dust, because all coins will be send to one address
            var fee = (long)((tx.VirtualSize() + estimatedSigSize) * currency.FeeRate);

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

            tx = currency.CreateP2PkhTx(
                unspentOutputs: new ITxOutput[] { swapOutput },
                destinationAddress: redeemAddress,
                changeAddress: redeemAddress,
                amount: amount - fee,
                fee: fee,
                lockTime: DateTimeOffset.MinValue);

            if (sequenceNumber > 0)
            {
                tx.SetSequenceNumber(sequenceNumber);
            }

            return(Task.FromResult(tx));
        }
コード例 #24
0
        public async void GetUnspentOutputsTest(
            BitcoinBasedCurrency currency,
            string baseUri,
            string address)
        {
            var api        = new InsightApi(currency, baseUri);
            var utxoResult = await api.GetUnspentOutputsAsync(address);

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

            var utxo = utxoResult.Value;

            Assert.NotNull(utxo);
        }
コード例 #25
0
 public static ReceiveViewModel CreateViewModel(
     IAtomexApp app,
     Currency currency)
 {
     return(currency switch
     {
         BitcoinBasedCurrency _ => new ReceiveViewModel(app, currency),
         ERC20 _ => new ReceiveViewModel(app, currency),
         Ethereum _ => new EthereumReceiveViewModel(app, currency),
         NYX _ => new ReceiveViewModel(app, currency),
         FA2 _ => new ReceiveViewModel(app, currency),
         FA12 _ => new ReceiveViewModel(app, currency),
         Tezos _ => new TezosReceiveViewModel(app, currency),
         _ => throw new NotSupportedException($"Can't create receive view model for {currency.Name}. This currency is not supported."),
     });
コード例 #26
0
        public async void IsTransactionOutputSpentTest(
            BitcoinBasedCurrency currency,
            string baseUri,
            string txId,
            uint outputNo,
            string spentTxId,
            uint spentIndex)
        {
            var api        = new InsightApi(currency, baseUri);
            var spentPoint = await api.IsTransactionOutputSpent(txId, outputNo);

            Assert.NotNull(spentPoint);
            Assert.Equal(spentTxId, spentPoint.Hash);
            Assert.Equal(spentIndex, spentPoint.Index);
        }
コード例 #27
0
        public async void GetInputTest(
            BitcoinBasedCurrency currency,
            string baseUri,
            string txId,
            uint inputIndex,
            string prevTxId,
            uint prevTxOutputIndex)
        {
            var api   = new InsightApi(currency, baseUri);
            var input = await api.GetInputAsync(txId, inputIndex);

            Assert.NotNull(input);
            Assert.Equal(prevTxId, input.Hash);
            Assert.Equal(prevTxOutputIndex, input.Index);
        }
コード例 #28
0
 public static SendViewModel CreateViewModel(
     IAtomexApp app,
     Currency currency)
 {
     return(currency switch
     {
         BitcoinBasedCurrency _ => (SendViewModel) new BitcoinBasedSendViewModel(app, currency),
         ERC20 _ => (SendViewModel) new Erc20SendViewModel(app, currency),
         Ethereum _ => (SendViewModel) new EthereumSendViewModel(app, currency),
         NYX _ => (SendViewModel) new Fa12SendViewModel(app, currency),
         FA2 _ => (SendViewModel) new Fa12SendViewModel(app, currency),
         FA12 _ => (SendViewModel) new Fa12SendViewModel(app, currency),
         Tezos _ => (SendViewModel) new TezosSendViewModel(app, currency),
         _ => throw new NotSupportedException($"Can't create send view model for {currency.Name}. This currency is not supported."),
     });
コード例 #29
0
 public static IBitcoinBasedTransaction CreateSegwitPaymentTx(
     BitcoinBasedCurrency 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));
 }
コード例 #30
0
        private async Task <IBitcoinBasedTransaction> GetPaymentTxAsync(
            BitcoinBasedCurrency currency,
            string txId,
            CancellationToken cancellationToken = default)
        {
            var attempts = 0;

            while (attempts < DefaultGetTransactionAttempts)
            {
                attempts++;

                var txResult = await currency.BlockchainApi
                               .TryGetTransactionAsync(txId, cancellationToken : cancellationToken)
                               .ConfigureAwait(false);

                if (txResult != null &&
                    txResult.HasError &&
                    txResult.Error.Code != (int)HttpStatusCode.NotFound &&
                    txResult.Error.Code != (int)HttpStatusCode.GatewayTimeout &&
                    txResult.Error.Code != (int)HttpStatusCode.ServiceUnavailable &&
                    txResult.Error.Code != (int)HttpStatusCode.InternalServerError &&
                    txResult.Error.Code != HttpHelper.SslHandshakeFailed &&
                    txResult.Error.Code != Errors.RequestError)
                {
                    Log.Error("Error while get transaction {@txId}. Code: {@code}. Description: {@desc}",
                              txId,
                              txResult.Error.Code,
                              txResult.Error.Description);

                    return(null);
                }

                var tx = txResult?.Value;

                if (tx != null)
                {
                    return((IBitcoinBasedTransaction)tx);
                }

                await Task.Delay(GetTransactionInterval, cancellationToken)
                .ConfigureAwait(false);
            }

            throw new InternalException(
                      code: Errors.SwapError,
                      description: $"Transaction with id {txId} not found");
        }