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();
 }
示例#2
0
        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;
            }
            }
        }
示例#3
0
        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");
        }
    }
示例#5
0
        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
            });
        }