public BitcoinConnector(string oracleAddress, string endpoint, Channel <Deposit> depositStream, Channel <WithdrawInfo> withdrawStream) { this.depositStream = depositStream; this.withdrawStream = withdrawStream; this.oracleAddress = TrackedSource.Create(new BitcoinPubKeyAddress(oracleAddress)); client = new ExplorerClient(new NBXplorerNetworkProvider(NetworkType.Testnet).GetBTC(), new Uri(endpoint)); client.SetNoAuth(); }
public async Task TrackSpendableOutput(NRustLightningNetwork network, SpendableOutputDescriptor desc, CancellationToken ct = default) { var client = _nbXplorerClientProvider.GetClient(network); switch (desc) { case SpendableOutputDescriptor.StaticOutput staticOutput: { var addr = staticOutput.Item.Output.ScriptPubKey.GetDestinationAddress(network.NBitcoinNetwork); var s = new AddressTrackedSource(addr); await client.TrackAsync(s, ct); await client.RPCClient.ImportAddressAsync(addr); break; } case SpendableOutputDescriptor.DynamicOutputP2WSH p2wshOutput: { var(param1, param2) = p2wshOutput.Item.KeyDerivationParams.ToValueTuple(); var amountSat = (ulong)p2wshOutput.Item.Output.Value.Satoshi; var channelKeys = _keysRepository.DeriveChannelKeys(amountSat, param1, param2); var delayedPaymentKey = Generators.derivePrivKey(_secp256k1Ctx, channelKeys.DelayedPaymentBaseKey, p2wshOutput.Item.PerCommitmentPoint.PubKey); var toSelfDelay = p2wshOutput.Item.ToSelfDelay; var revokeableRedeemScript = _keysRepository.GetRevokeableRedeemScript(p2wshOutput.Item.RemoteRevocationPubKey, toSelfDelay, delayedPaymentKey.PubKey); Debug.Assert(p2wshOutput.Item.Output.ScriptPubKey.Equals(revokeableRedeemScript.WitHash.ScriptPubKey)); var addr = revokeableRedeemScript.WitHash.ScriptPubKey.GetDestinationAddress(network.NBitcoinNetwork); var s = new AddressTrackedSource(addr); await client.TrackAsync(s, ct); await client.RPCClient.ImportAddressAsync(addr); break; } case SpendableOutputDescriptor.StaticOutputRemotePayment remoteOutput: { var(p1, p2) = remoteOutput.Item.KeyDerivationParams.ToValueTuple(); var amountSat = (ulong)remoteOutput.Item.Output.Value; var keys = _keysRepository.DeriveChannelKeys(amountSat, p1, p2); Debug.Assert( keys.PaymentKey.PubKey.WitHash.ScriptPubKey.Equals(remoteOutput.Item.Output.ScriptPubKey)); var addr = remoteOutput.Item.Output.ScriptPubKey.GetDestinationAddress(network.NBitcoinNetwork); await client.TrackAsync(new AddressTrackedSource(addr), ct); await client.RPCClient.ImportAddressAsync(addr); break; } } }
private static TrackedSource GetTrackedSource(DerivationStrategyBase derivationScheme, BitcoinAddress address) { TrackedSource trackedSource = null; if (address != null) { trackedSource = new AddressTrackedSource(address); } if (derivationScheme != null) { trackedSource = new DerivationSchemeTrackedSource(derivationScheme); } return(trackedSource); }
private async Task UpdatePayoutsAwaitingForPayment(NewOnChainTransactionEvent newTransaction, AddressTrackedSource addressTrackedSource) { try { var network = _btcPayNetworkProvider.GetNetwork <BTCPayNetwork>(newTransaction.CryptoCode); var destinationSum = newTransaction.NewTransactionEvent.Outputs.Sum(output => output.Value.GetValue(network)); var destination = addressTrackedSource.Address.ToString(); var paymentMethodId = new PaymentMethodId(newTransaction.CryptoCode, BitcoinPaymentType.Instance); await using var ctx = _dbContextFactory.CreateContext(); var payouts = await ctx.Payouts .Include(o => o.StoreData) .Include(o => o.PullPaymentData) .Where(p => p.State == PayoutState.AwaitingPayment) .Where(p => p.PaymentMethodId == paymentMethodId.ToString()) #pragma warning disable CA1307 // Specify StringComparison .Where(p => destination.Equals(p.Destination)) #pragma warning restore CA1307 // Specify StringComparison .ToListAsync(); var payoutByDestination = payouts.ToDictionary(p => p.Destination); if (!payoutByDestination.TryGetValue(destination, out var payout)) { return; } var payoutBlob = payout.GetBlob(_jsonSerializerSettings); if (payoutBlob.CryptoAmount is null || // The round up here is not strictly necessary, this is temporary to fix existing payout before we // were properly roundup the crypto amount destinationSum != BTCPayServer.Extensions.RoundUp(payoutBlob.CryptoAmount.Value, network.Divisibility)) { return; } var derivationSchemeSettings = payout.StoreData .GetDerivationSchemeSettings(_btcPayNetworkProvider, newTransaction.CryptoCode).AccountDerivation; var storeWalletMatched = (await _explorerClientProvider.GetExplorerClient(newTransaction.CryptoCode) .GetTransactionAsync(derivationSchemeSettings, newTransaction.NewTransactionEvent.TransactionData.TransactionHash)); //if the wallet related to the store related to the payout does not have the tx: it is external var isInternal = storeWalletMatched is { }; var proof = ParseProof(payout) as PayoutTransactionOnChainBlob ?? new PayoutTransactionOnChainBlob() { Accounted = isInternal }; var txId = newTransaction.NewTransactionEvent.TransactionData.TransactionHash; if (!proof.Candidates.Add(txId)) { return; } if (isInternal) { payout.State = PayoutState.InProgress; var walletId = new WalletId(payout.StoreDataId, newTransaction.CryptoCode); _eventAggregator.Publish(new UpdateTransactionLabel(walletId, newTransaction.NewTransactionEvent.TransactionData.TransactionHash, UpdateTransactionLabel.PayoutTemplate(new () { { payout.PullPaymentDataId ?? "", new List <string> { payout.Id } } }, walletId.ToString()))); } else { await _notificationSender.SendNotification(new StoreScope(payout.StoreDataId), new ExternalPayoutTransactionNotification() { PaymentMethod = payout.PaymentMethodId, PayoutId = payout.Id, StoreId = payout.StoreDataId }); } proof.TransactionId ??= txId; SetProofBlob(payout, proof); await ctx.SaveChangesAsync(); } catch (Exception ex) { Logs.PayServer.LogWarning(ex, "Error while processing a transaction in the pull payment hosted service"); } }
public async Task <UTXOChangesWithMetadata> ListUnspent(NRustLightningNetwork n) { var _cli = _nbXplorerClientProvider.GetClient(n); var deriv = await GetOurDerivationStrategyAsync(n); var confirmedUtxo = new List <UTXOChangeWithMetadata>(); var unconfirmedUtxo = new List <UTXOChangeWithMetadata>(); var confirmedSpentOutpoints = new List <OutPoint>(); var unconfirmedSpentOutpoints = new List <OutPoint>(); var nativeFundsResponse = await _cli.GetUTXOsAsync(deriv); foreach (var utxo in nativeFundsResponse.Confirmed.UTXOs) { var item = new UTXOChangeWithMetadata(new UTXO(utxo), UTXOKind.UserDeposit, new DerivationSchemeTrackedSource(deriv)); confirmedUtxo.Add(item); } foreach (var utxo in nativeFundsResponse.Unconfirmed.UTXOs) { unconfirmedUtxo.Add(new UTXOChangeWithMetadata(new UTXO(utxo), UTXOKind.UserDeposit, new DerivationSchemeTrackedSource(deriv))); } confirmedSpentOutpoints.AddRange(nativeFundsResponse.Confirmed.SpentOutpoints); unconfirmedSpentOutpoints.AddRange(nativeFundsResponse.Unconfirmed.SpentOutpoints); var repo = _repositoryProvider.GetRepository(n); // TODO: Refactor when https://github.com/dgarage/NBXplorer/issues/291 is ready await foreach (var o in repo.GetAllSpendableOutputDescriptors()) { var addr = o.Output.ScriptPubKey.GetDestinationAddress(n.NBitcoinNetwork); var ts = new AddressTrackedSource(addr); var lnUTXOResposne = await _cli.GetUTXOsAsync(ts); foreach (var utxo in lnUTXOResposne.Confirmed.UTXOs) { confirmedUtxo.Add(new UTXOChangeWithMetadata(new UTXO(utxo), o.GetKind(), ts)); } foreach (var utxo in lnUTXOResposne.Unconfirmed.UTXOs) { unconfirmedUtxo.Add(new UTXOChangeWithMetadata(new UTXO(utxo), o.GetKind(), ts)); } confirmedSpentOutpoints.AddRange(lnUTXOResposne.Confirmed.SpentOutpoints); unconfirmedSpentOutpoints.AddRange(lnUTXOResposne.Unconfirmed.SpentOutpoints); } ; var confirmed = new UTXOChangeWithSpentOutput() { UTXO = confirmedUtxo, SpentOutPoint = confirmedSpentOutpoints }; var unconfirmed = new UTXOChangeWithSpentOutput() { UTXO = unconfirmedUtxo, SpentOutPoint = unconfirmedSpentOutpoints }; return(new UTXOChangesWithMetadata() { Confirmed = confirmed, UnConfirmed = unconfirmed, CurrentHeight = nativeFundsResponse.CurrentHeight }); }