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"); }
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); }
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); }
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))); }
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()) }); }
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)); }
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()); }
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); }
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); }
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 ?? ""); }
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 }
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())); }
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); }
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); }
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); }
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; }
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); }
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)); }
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); }
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); }
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; }
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)); }
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); }
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."), });
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); }
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); }
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."), });
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)); }
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"); }