mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 14:34:23 +01:00
Liquid & Liquid Assets Support (#1118)
This commit is contained in:
committed by
Nicolas Dorier
parent
0485a9178d
commit
4d7480db15
@@ -17,7 +17,6 @@ namespace BTCPayServer
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Bitcoin",
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://blockstream.info/tx/{0}" : "https://blockstream.info/testnet/tx/{0}",
|
||||
NBitcoinNetwork = nbxplorerNetwork.NBitcoinNetwork,
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "bitcoin",
|
||||
CryptoImagePath = "imlegacy/bitcoin.svg",
|
||||
|
||||
@@ -12,7 +12,6 @@ namespace BTCPayServer
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "BGold",
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://explorer.bitcoingold.org/insight/tx/{0}/" : "https://test-explorer.bitcoingold.org/insight/tx/{0}",
|
||||
NBitcoinNetwork = nbxplorerNetwork.NBitcoinNetwork,
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "bitcoingold",
|
||||
DefaultRateRules = new[]
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace BTCPayServer
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Bitcoinplus",
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://chainz.cryptoid.info/xbc/tx.dws?{0}" : "https://chainz.cryptoid.info/xbc/tx.dws?{0}",
|
||||
NBitcoinNetwork = nbxplorerNetwork.NBitcoinNetwork,
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "bitcoinplus",
|
||||
DefaultRateRules = new[]
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace BTCPayServer
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Bitcore",
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://insight.bitcore.cc/tx/{0}" : "https://insight.bitcore.cc/tx/{0}",
|
||||
NBitcoinNetwork = nbxplorerNetwork.NBitcoinNetwork,
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "bitcore",
|
||||
DefaultRateRules = new[]
|
||||
|
||||
@@ -15,7 +15,6 @@ namespace BTCPayServer
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet
|
||||
? "https://insight.dash.org/insight/tx/{0}"
|
||||
: "https://testnet-insight.dashevo.org/insight/tx/{0}",
|
||||
NBitcoinNetwork = nbxplorerNetwork.NBitcoinNetwork,
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "dash",
|
||||
DefaultRateRules = new[]
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace BTCPayServer
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Dogecoin",
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://dogechain.info/tx/{0}" : "https://dogechain.info/tx/{0}",
|
||||
NBitcoinNetwork = nbxplorerNetwork.NBitcoinNetwork,
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "dogecoin",
|
||||
DefaultRateRules = new[]
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace BTCPayServer
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Feathercoin",
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://explorer.feathercoin.com/tx/{0}" : "https://explorer.feathercoin.com/tx/{0}",
|
||||
NBitcoinNetwork = nbxplorerNetwork.NBitcoinNetwork,
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "feathercoin",
|
||||
DefaultRateRules = new[]
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace BTCPayServer
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet
|
||||
? "https://chainz.cryptoid.info/grs/tx.dws?{0}.htm"
|
||||
: "https://chainz.cryptoid.info/grs-test/tx.dws?{0}.htm",
|
||||
NBitcoinNetwork = nbxplorerNetwork.NBitcoinNetwork,
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "groestlcoin",
|
||||
DefaultRateRules = new[]
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace BTCPayServer
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet
|
||||
? "https://live.blockcypher.com/ltc/tx/{0}/"
|
||||
: "http://explorer.litecointools.com/tx/{0}",
|
||||
NBitcoinNetwork = nbxplorerNetwork.NBitcoinNetwork,
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "litecoin",
|
||||
CryptoImagePath = "imlegacy/litecoin.svg",
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace BTCPayServer
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Monacoin",
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://mona.insight.monaco-ex.org/insight/tx/{0}" : "https://testnet-mona.insight.monaco-ex.org/insight/tx/{0}",
|
||||
NBitcoinNetwork = nbxplorerNetwork.NBitcoinNetwork,
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "monacoin",
|
||||
DefaultRateRules = new[]
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace BTCPayServer
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Polis",
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://insight.polispay.org/tx/{0}" : "https://insight.polispay.org/tx/{0}",
|
||||
NBitcoinNetwork = nbxplorerNetwork.NBitcoinNetwork,
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "polis",
|
||||
DefaultRateRules = new[]
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace BTCPayServer
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Ufo",
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://chainz.cryptoid.info/ufo/tx.dws?{0}" : "https://chainz.cryptoid.info/ufo/tx.dws?{0}",
|
||||
NBitcoinNetwork = nbxplorerNetwork.NBitcoinNetwork,
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "ufo",
|
||||
DefaultRateRules = new[]
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace BTCPayServer
|
||||
CryptoCode = nbxplorerNetwork.CryptoCode,
|
||||
DisplayName = "Viacoin",
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://explorer.viacoin.org/tx/{0}" : "https://explorer.viacoin.org/tx/{0}",
|
||||
NBitcoinNetwork = nbxplorerNetwork.NBitcoinNetwork,
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "viacoin",
|
||||
DefaultRateRules = new[]
|
||||
|
||||
@@ -47,6 +47,8 @@ namespace BTCPayServer
|
||||
_NBXplorerNetworkProvider = new NBXplorerNetworkProvider(networkType);
|
||||
NetworkType = networkType;
|
||||
InitBitcoin();
|
||||
InitLiquid();
|
||||
InitLiquidAssets();
|
||||
InitLitecoin();
|
||||
InitBitcore();
|
||||
InitDogecoin();
|
||||
@@ -93,6 +95,12 @@ namespace BTCPayServer
|
||||
[Obsolete("To use only for legacy stuff")]
|
||||
public BTCPayNetwork BTC => GetNetwork<BTCPayNetwork>("BTC");
|
||||
|
||||
public void Add(BTCPayNetwork network)
|
||||
{
|
||||
if (network.NBitcoinNetwork == null)
|
||||
return;
|
||||
Add(network as BTCPayNetworkBase);
|
||||
}
|
||||
public void Add(BTCPayNetworkBase network)
|
||||
{
|
||||
_Networks.Add(network.CryptoCode.ToUpperInvariant(), network);
|
||||
@@ -109,7 +117,7 @@ namespace BTCPayServer
|
||||
}
|
||||
public BTCPayNetworkBase GetNetwork(string cryptoCode)
|
||||
{
|
||||
return GetNetwork<BTCPayNetworkBase>(cryptoCode);
|
||||
return GetNetwork<BTCPayNetworkBase>(cryptoCode.ToUpperInvariant());
|
||||
}
|
||||
public T GetNetwork<T>(string cryptoCode) where T: BTCPayNetworkBase
|
||||
{
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NBitcoin;
|
||||
using NBitcoin.Altcoins;
|
||||
using NBitcoin.Altcoins.Elements;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitLiquid()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("LBTC");
|
||||
Add(new ElementsBTCPayNetwork()
|
||||
{
|
||||
AssetId = NetworkType == NetworkType.Mainnet ? ElementsParams<Liquid>.PeggedAssetId: ElementsParams<Liquid.LiquidRegtest>.PeggedAssetId,
|
||||
CryptoCode = "LBTC",
|
||||
NetworkCryptoCode = "LBTC",
|
||||
DisplayName = "Liquid Bitcoin",
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"LBTC_X = LBTC_BTC * BTC_X",
|
||||
"LBTC_BTC = 1",
|
||||
},
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://blockstream.info/liquid/tx/{0}" : "https://blockstream.info/testnet/liquid/tx/{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "liquidnetwork",
|
||||
CryptoImagePath = "imlegacy/liquid.svg",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
|
||||
SupportRBF = true,
|
||||
//https://github.com/spesmilo/electrum/blob/11733d6bc271646a00b69ff07657119598874da4/electrum/constants.py
|
||||
ElectrumMapping = NetworkType == NetworkType.Mainnet
|
||||
? new Dictionary<uint, DerivationType>()
|
||||
{
|
||||
{0x0488b21eU, DerivationType.Legacy }, // xpub
|
||||
{0x049d7cb2U, DerivationType.SegwitP2SH }, // ypub
|
||||
{0x4b24746U, DerivationType.Segwit }, //zpub
|
||||
}
|
||||
: new Dictionary<uint, DerivationType>()
|
||||
{
|
||||
{0x043587cfU, DerivationType.Legacy},
|
||||
{0x044a5262U, DerivationType.SegwitP2SH},
|
||||
{0x045f1cf6U, DerivationType.Segwit}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public partial class BTCPayNetworkProvider
|
||||
{
|
||||
public void InitLiquidAssets()
|
||||
{
|
||||
var nbxplorerNetwork = NBXplorerNetworkProvider.GetFromCryptoCode("LBTC");
|
||||
Add(new ElementsBTCPayNetwork()
|
||||
{
|
||||
CryptoCode = "USDt",
|
||||
NetworkCryptoCode = "LBTC",
|
||||
DefaultRateRules = new[]
|
||||
{
|
||||
"USDT_UST = 1",
|
||||
"USDT_X = USDT_BTC * BTC_X",
|
||||
"USDT_BTC = bitfinex(UST_BTC)",
|
||||
},
|
||||
AssetId = new uint256("ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"),
|
||||
DisplayName = "Tether USD",
|
||||
BlockExplorerLink = NetworkType == NetworkType.Mainnet ? "https://blockstream.info/liquid/tx/{0}" : "https://blockstream.info/testnet/liquid/tx/{0}",
|
||||
NBXplorerNetwork = nbxplorerNetwork,
|
||||
UriScheme = "liquidnetwork",
|
||||
CryptoImagePath = "imlegacy/liquid-tether.svg",
|
||||
DefaultSettings = BTCPayDefaultSettings.GetDefaultSettings(NetworkType),
|
||||
CoinType = NetworkType == NetworkType.Mainnet ? new KeyPath("1776'") : new KeyPath("1'"),
|
||||
SupportRBF = true,
|
||||
//https://github.com/spesmilo/electrum/blob/11733d6bc271646a00b69ff07657119598874da4/electrum/constants.py
|
||||
ElectrumMapping = NetworkType == NetworkType.Mainnet
|
||||
? new Dictionary<uint, DerivationType>()
|
||||
{
|
||||
{0x0488b21eU, DerivationType.Legacy }, // xpub
|
||||
{0x049d7cb2U, DerivationType.SegwitP2SH }, // ypub
|
||||
{0x4b24746U, DerivationType.Segwit }, //zpub
|
||||
}
|
||||
: new Dictionary<uint, DerivationType>()
|
||||
{
|
||||
{0x043587cfU, DerivationType.Legacy},
|
||||
{0x044a5262U, DerivationType.SegwitP2SH},
|
||||
{0x045f1cf6U, DerivationType.Segwit}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
using NBXplorer.Models;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
public class ElementsBTCPayNetwork:BTCPayNetwork
|
||||
{
|
||||
public string NetworkCryptoCode { get; set; }
|
||||
public uint256 AssetId { get; set; }
|
||||
public override bool WalletSupported { get; set; } = false;
|
||||
public int Divisibility { get; set; } = 8;
|
||||
|
||||
public override IEnumerable<(MatchedOutput matchedOutput, OutPoint outPoint)> GetValidOutputs(NewTransactionEvent evtOutputs)
|
||||
{
|
||||
return evtOutputs.Outputs.Where(output =>
|
||||
output.Value is AssetMoney assetMoney && assetMoney.AssetId == AssetId).Select(output =>
|
||||
{
|
||||
var outpoint = new OutPoint(evtOutputs.TransactionData.TransactionHash, output.Index);
|
||||
return (output, outpoint);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
using NBXplorer.Models;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace BTCPayServer
|
||||
@@ -46,7 +47,7 @@ namespace BTCPayServer
|
||||
|
||||
public class BTCPayNetwork:BTCPayNetworkBase
|
||||
{
|
||||
public Network NBitcoinNetwork { get; set; }
|
||||
public Network NBitcoinNetwork { get { return NBXplorerNetwork?.NBitcoinNetwork; } }
|
||||
public NBXplorer.NBXplorerNetwork NBXplorerNetwork { get; set; }
|
||||
public bool SupportRBF { get; internal set; }
|
||||
public string LightningImagePath { get; set; }
|
||||
@@ -55,6 +56,8 @@ namespace BTCPayServer
|
||||
|
||||
public Dictionary<uint, DerivationType> ElectrumMapping = new Dictionary<uint, DerivationType>();
|
||||
|
||||
public virtual bool WalletSupported { get; set; } = true;
|
||||
|
||||
public int MaxTrackedConfirmation { get; internal set; } = 6;
|
||||
public string UriScheme { get; internal set; }
|
||||
public KeyPath GetRootKeyPath(DerivationType type)
|
||||
@@ -100,6 +103,14 @@ namespace BTCPayServer
|
||||
{
|
||||
return NBXplorerNetwork.Serializer.ToString(obj);
|
||||
}
|
||||
public virtual IEnumerable<(MatchedOutput matchedOutput, OutPoint outPoint)> GetValidOutputs(NewTransactionEvent evtOutputs)
|
||||
{
|
||||
return evtOutputs.Outputs.Select(output =>
|
||||
{
|
||||
var outpoint = new OutPoint(evtOutputs.TransactionData.TransactionHash, output.Index);
|
||||
return (output, outpoint);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class BTCPayNetworkBase
|
||||
|
||||
@@ -63,6 +63,7 @@ namespace BTCPayServer.Tests
|
||||
}
|
||||
|
||||
public Uri LTCNBXplorerUri { get; set; }
|
||||
public Uri LBTCNBXplorerUri { get; set; }
|
||||
|
||||
public Uri ServerUri
|
||||
{
|
||||
@@ -93,6 +94,7 @@ namespace BTCPayServer.Tests
|
||||
|
||||
public bool MockRates { get; set; } = true;
|
||||
|
||||
public List<string> Chains { get; set; } = new List<string>(){"BTC", "LTC"};
|
||||
public async Task StartAsync()
|
||||
{
|
||||
if (!Directory.Exists(_Directory))
|
||||
@@ -109,20 +111,33 @@ namespace BTCPayServer.Tests
|
||||
config.AppendLine($"bind=0.0.0.0");
|
||||
}
|
||||
config.AppendLine($"port={Port}");
|
||||
config.AppendLine($"chains=btc,ltc");
|
||||
|
||||
config.AppendLine($"chains={string.Join(',', Chains)}");
|
||||
if (Chains.Contains("BTC", StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
config.AppendLine($"btc.explorer.url={NBXplorerUri.AbsoluteUri}");
|
||||
config.AppendLine($"btc.explorer.cookiefile=0");
|
||||
config.AppendLine("allow-admin-registration=1");
|
||||
config.AppendLine($"ltc.explorer.url={LTCNBXplorerUri.AbsoluteUri}");
|
||||
config.AppendLine($"ltc.explorer.cookiefile=0");
|
||||
config.AppendLine($"btc.lightning={IntegratedLightning.AbsoluteUri}");
|
||||
config.AppendLine($"torrcfile={TestUtils.GetTestDataFullPath("Tor/torrc")}");
|
||||
config.AppendLine($"debuglog=debug.log");
|
||||
|
||||
var localLndBackupFile = Path.Combine(_Directory, "walletunlock.json");
|
||||
File.Copy(TestUtils.GetTestDataFullPath("LndSeedBackup/walletunlock.json"), localLndBackupFile, true);
|
||||
config.AppendLine($"btc.external.lndseedbackup={localLndBackupFile}");
|
||||
}
|
||||
|
||||
if (Chains.Contains("LTC", StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
config.AppendLine($"ltc.explorer.url={LTCNBXplorerUri.AbsoluteUri}");
|
||||
config.AppendLine($"ltc.explorer.cookiefile=0");
|
||||
}
|
||||
if (Chains.Contains("LBTC", StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
config.AppendLine($"lbtc.explorer.url={LBTCNBXplorerUri.AbsoluteUri}");
|
||||
config.AppendLine($"lbtc.explorer.cookiefile=0");
|
||||
}
|
||||
config.AppendLine("allow-admin-registration=1");
|
||||
|
||||
config.AppendLine($"torrcfile={TestUtils.GetTestDataFullPath("Tor/torrc")}");
|
||||
config.AppendLine($"debuglog=debug.log");
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(SSHPassword) && string.IsNullOrEmpty(SSHKeyFile))
|
||||
config.AppendLine($"sshpassword={SSHPassword}");
|
||||
if (!string.IsNullOrEmpty(SSHKeyFile))
|
||||
@@ -231,6 +246,16 @@ namespace BTCPayServer.Tests
|
||||
BidAsk = new BidAsk(0.004m)
|
||||
});
|
||||
rateProvider.Providers.Add("bittrex", bittrex);
|
||||
|
||||
|
||||
var bitfinex = new MockRateProvider();
|
||||
bitfinex.ExchangeRates.Add(new Rating.ExchangeRate()
|
||||
{
|
||||
Exchange = "bitfinex",
|
||||
CurrencyPair = CurrencyPair.Parse("UST_BTC"),
|
||||
BidAsk = new BidAsk(0.000136m)
|
||||
});
|
||||
rateProvider.Providers.Add("bitfinex", bitfinex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
124
BTCPayServer.Tests/ElementsTests.cs
Normal file
124
BTCPayServer.Tests/ElementsTests.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Configuration;
|
||||
using BTCPayServer.Controllers;
|
||||
using BTCPayServer.Models.WalletViewModels;
|
||||
using BTCPayServer.Services.Wallets;
|
||||
using BTCPayServer.Tests.Logging;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Configuration.Memory;
|
||||
using NBitcoin;
|
||||
using NBitcoin.RPC;
|
||||
using NBitpayClient;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace BTCPayServer.Tests
|
||||
{
|
||||
public class ElementsTests
|
||||
{
|
||||
|
||||
public const int TestTimeout = 60_000;
|
||||
public ElementsTests(ITestOutputHelper helper)
|
||||
{
|
||||
Logs.Tester = new XUnitLog(helper) { Name = "Tests" };
|
||||
Logs.LogProvider = new XUnitLogProvider(helper);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task OnlyShowSupportedWallets()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.PayTester.Chains.Add("LBTC");
|
||||
await tester.StartAsync();
|
||||
await tester.EnsureChannelsSetup();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
user.RegisterDerivationScheme("LBTC");
|
||||
user.RegisterDerivationScheme("BTC");
|
||||
user.RegisterDerivationScheme("USDT");
|
||||
|
||||
Assert.Single(Assert.IsType<ListWalletsViewModel>(Assert.IsType<ViewResult>(await user.GetController<WalletsController>().ListWallets()).Model).Wallets);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Fast", "Fast")]
|
||||
public void LoadSubChainsAlways()
|
||||
{
|
||||
var options = new BTCPayServerOptions();
|
||||
options.LoadArgs(new ConfigurationRoot(new List<IConfigurationProvider>()
|
||||
{
|
||||
new MemoryConfigurationProvider(new MemoryConfigurationSource()
|
||||
{
|
||||
InitialData = new[]
|
||||
{
|
||||
new KeyValuePair<string, string>("chains", "usdt"),
|
||||
}
|
||||
})
|
||||
}));
|
||||
|
||||
Assert.NotNull(options.NetworkProvider.GetNetwork("LBTC"));
|
||||
Assert.NotNull(options.NetworkProvider.GetNetwork("USDT"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ElementsAssetsAreHandledCorrectly()
|
||||
{
|
||||
using (var tester = ServerTester.Create())
|
||||
{
|
||||
tester.PayTester.Chains.Add("LBTC");
|
||||
await tester.StartAsync();
|
||||
var user = tester.NewAccount();
|
||||
user.GrantAccess();
|
||||
user.RegisterDerivationScheme("LBTC");
|
||||
user.RegisterDerivationScheme("USDT");
|
||||
|
||||
//no tether on our regtest, lets create it and set it
|
||||
var tether = tester.NetworkProvider.GetNetwork<ElementsBTCPayNetwork>("USDT");
|
||||
var lbtc = tester.NetworkProvider.GetNetwork<ElementsBTCPayNetwork>("LBTC");
|
||||
var issueAssetResult = await tester.LBTCExplorerNode.SendCommandAsync("issueasset", 100000, 0);
|
||||
tether.AssetId = uint256.Parse(issueAssetResult.Result["asset"].ToString());
|
||||
((ElementsBTCPayNetwork)tester.PayTester.GetService<BTCPayWalletProvider>().GetWallet("USDT").Network)
|
||||
.AssetId = tether.AssetId;
|
||||
Logs.Tester.LogInformation($"Asset is {tether.AssetId}");
|
||||
Assert.Equal(tether.AssetId, tester.NetworkProvider.GetNetwork<ElementsBTCPayNetwork>("USDT").AssetId);
|
||||
Assert.Equal(tether.AssetId, ((ElementsBTCPayNetwork)tester.PayTester.GetService<BTCPayWalletProvider>().GetWallet("USDT").Network).AssetId);
|
||||
//test: register 2 assets on the same elements network and make sure paying an invoice on one does not affect the other in any way
|
||||
var invoice = await user.BitPay.CreateInvoiceAsync(new Invoice(0.1m, "BTC"));
|
||||
Assert.Equal(2, invoice.SupportedTransactionCurrencies.Count);
|
||||
var ci = invoice.CryptoInfo.Single(info => info.CryptoCode.Equals("LBTC"));
|
||||
//1 lbtc = 1 btc
|
||||
Assert.Equal(1, ci.Rate);
|
||||
var star = await tester.LBTCExplorerNode.SendCommandAsync("sendtoaddress", ci.Address,ci.Due, "", "", false, true,
|
||||
1, "UNSET", lbtc.AssetId);
|
||||
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal("paid", localInvoice.Status);
|
||||
Assert.Single(localInvoice.CryptoInfo.Single(info => info.CryptoCode.Equals("LBTC")).Payments);
|
||||
});
|
||||
|
||||
invoice = await user.BitPay.CreateInvoiceAsync(new Invoice(0.1m, "BTC"));
|
||||
|
||||
ci = invoice.CryptoInfo.Single(info => info.CryptoCode.Equals("USDT"));
|
||||
Assert.Equal(2, invoice.SupportedTransactionCurrencies.Count);
|
||||
star = await tester.LBTCExplorerNode.SendCommandAsync("sendtoaddress", ci.Address, ci.Due, "", "", false, true,
|
||||
1, "UNSET", tether.AssetId);
|
||||
|
||||
TestUtils.Eventually(() =>
|
||||
{
|
||||
var localInvoice = user.BitPay.GetInvoice(invoice.Id, Facade.Merchant);
|
||||
Assert.Equal("paid", localInvoice.Status);
|
||||
Assert.Single(localInvoice.CryptoInfo.Single(info => info.CryptoCode.Equals("USDT", StringComparison.InvariantCultureIgnoreCase)).Payments);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,9 +47,11 @@ namespace BTCPayServer.Tests
|
||||
ExplorerNode = new RPCClient(RPCCredentialString.Parse(GetEnvironment("TESTS_BTCRPCCONNECTION", "server=http://127.0.0.1:43782;ceiwHEbqWI83:DwubwWsoo3")), NetworkProvider.GetNetwork<BTCPayNetwork>("BTC").NBitcoinNetwork);
|
||||
ExplorerNode.ScanRPCCapabilities();
|
||||
LTCExplorerNode = new RPCClient(RPCCredentialString.Parse(GetEnvironment("TESTS_LTCRPCCONNECTION", "server=http://127.0.0.1:43783;ceiwHEbqWI83:DwubwWsoo3")), NetworkProvider.GetNetwork<BTCPayNetwork>("LTC").NBitcoinNetwork);
|
||||
LBTCExplorerNode = new RPCClient(RPCCredentialString.Parse(GetEnvironment("TESTS_LBTCRPCCONNECTION", "server=http://127.0.0.1:19332;liquid:liquid")), NetworkProvider.GetNetwork<BTCPayNetwork>("LBTC").NBitcoinNetwork);
|
||||
|
||||
ExplorerClient = new ExplorerClient(NetworkProvider.GetNetwork<BTCPayNetwork>("BTC").NBXplorerNetwork, new Uri(GetEnvironment("TESTS_BTCNBXPLORERURL", "http://127.0.0.1:32838/")));
|
||||
LTCExplorerClient = new ExplorerClient(NetworkProvider.GetNetwork<BTCPayNetwork>("LTC").NBXplorerNetwork, new Uri(GetEnvironment("TESTS_LTCNBXPLORERURL", "http://127.0.0.1:32838/")));
|
||||
LBTCExplorerClient = new ExplorerClient(NetworkProvider.GetNetwork<BTCPayNetwork>("LBTC").NBXplorerNetwork, new Uri(GetEnvironment("TESTS_LBTCNBXPLORERURL", "http://127.0.0.1:32838/")));
|
||||
|
||||
var btc = NetworkProvider.GetNetwork<BTCPayNetwork>("BTC").NBitcoinNetwork;
|
||||
CustomerLightningD = LightningClientFactory.CreateClient(GetEnvironment("TEST_CUSTOMERLIGHTNINGD", "type=clightning;server=tcp://127.0.0.1:30992/"), btc);
|
||||
@@ -61,8 +63,10 @@ namespace BTCPayServer.Tests
|
||||
|
||||
PayTester = new BTCPayServerTester(Path.Combine(_Directory, "pay"))
|
||||
{
|
||||
|
||||
NBXplorerUri = ExplorerClient.Address,
|
||||
LTCNBXplorerUri = LTCExplorerClient.Address,
|
||||
LBTCNBXplorerUri = LTCExplorerClient.Address,
|
||||
TestDatabase = Enum.Parse<TestDatabases>(GetEnvironment("TESTS_DB", TestDatabases.Postgres.ToString()), true),
|
||||
Postgres = GetEnvironment("TESTS_POSTGRES", "User ID=postgres;Host=127.0.0.1;Port=39372;Database=btcpayserver"),
|
||||
MySQL = GetEnvironment("TESTS_MYSQL", "User ID=root;Host=127.0.0.1;Port=33036;Database=btcpayserver"),
|
||||
@@ -77,6 +81,7 @@ namespace BTCPayServer.Tests
|
||||
PayTester.SSHConnection = GetEnvironment("TESTS_SSHCONNECTION", "root@127.0.0.1:21622");
|
||||
}
|
||||
|
||||
|
||||
public bool Dockerized
|
||||
{
|
||||
get; set;
|
||||
@@ -149,11 +154,14 @@ namespace BTCPayServer.Tests
|
||||
get; set;
|
||||
}
|
||||
|
||||
public RPCClient LBTCExplorerNode { get; set; }
|
||||
|
||||
public ExplorerClient ExplorerClient
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public ExplorerClient LTCExplorerClient { get; set; }
|
||||
public ExplorerClient LBTCExplorerClient { get; set; }
|
||||
|
||||
HttpClient _Http = new HttpClient();
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace BTCPayServer.Tests
|
||||
SupportedNetwork = parent.NetworkProvider.GetNetwork<BTCPayNetwork>(cryptoCode);
|
||||
var store = parent.PayTester.GetController<StoresController>(UserId, StoreId);
|
||||
ExtKey = new ExtKey().GetWif(SupportedNetwork.NBitcoinNetwork);
|
||||
DerivationScheme = new DerivationStrategyFactory(SupportedNetwork.NBitcoinNetwork).Parse(ExtKey.Neuter().ToString() + (segwit ? "" : "-[legacy]"));
|
||||
DerivationScheme = SupportedNetwork.NBXplorerNetwork.DerivationStrategyFactory.Parse(ExtKey.Neuter().ToString() + (segwit ? "" : "-[legacy]"));
|
||||
await store.AddDerivationScheme(StoreId, new DerivationSchemeViewModel()
|
||||
{
|
||||
DerivationScheme = DerivationScheme.ToString(),
|
||||
|
||||
@@ -151,6 +151,7 @@ namespace BTCPayServer.Tests
|
||||
new LightningLikePaymentHandler(null, null, networkProvider, null),
|
||||
});
|
||||
InvoiceEntity invoiceEntity = new InvoiceEntity();
|
||||
invoiceEntity.Networks = networkProvider;
|
||||
invoiceEntity.Payments = new System.Collections.Generic.List<PaymentEntity>();
|
||||
invoiceEntity.ProductInformation = new ProductInformation() {Price = 100};
|
||||
PaymentMethodDictionary paymentMethods = new PaymentMethodDictionary();
|
||||
@@ -172,12 +173,15 @@ namespace BTCPayServer.Tests
|
||||
invoiceEntity.Payments.Add(
|
||||
new PaymentEntity()
|
||||
{
|
||||
|
||||
Accounted = true,
|
||||
CryptoCode = "BTC",
|
||||
NetworkFee = 0.00000100m
|
||||
NetworkFee = 0.00000100m,
|
||||
Network = networkProvider.GetNetwork("BTC"),
|
||||
}
|
||||
.SetCryptoPaymentData(new BitcoinLikePaymentData()
|
||||
{
|
||||
Network = networkProvider.GetNetwork("BTC"),
|
||||
Output = new TxOut() {Value = Money.Coins(0.00151263m)}
|
||||
}));
|
||||
accounting = btc.Calculate();
|
||||
@@ -186,10 +190,12 @@ namespace BTCPayServer.Tests
|
||||
{
|
||||
Accounted = true,
|
||||
CryptoCode = "BTC",
|
||||
NetworkFee = 0.00000100m
|
||||
NetworkFee = 0.00000100m,
|
||||
Network = networkProvider.GetNetwork("BTC")
|
||||
}
|
||||
.SetCryptoPaymentData(new BitcoinLikePaymentData()
|
||||
{
|
||||
Network = networkProvider.GetNetwork("BTC"),
|
||||
Output = new TxOut() {Value = accounting.Due}
|
||||
}));
|
||||
accounting = btc.Calculate();
|
||||
@@ -258,6 +264,7 @@ namespace BTCPayServer.Tests
|
||||
new LightningLikePaymentHandler(null, null, networkProvider, null),
|
||||
});
|
||||
var entity = new InvoiceEntity();
|
||||
entity.Networks = networkProvider;
|
||||
#pragma warning disable CS0618
|
||||
entity.Payments = new System.Collections.Generic.List<PaymentEntity>();
|
||||
entity.SetPaymentMethod(new PaymentMethod()
|
||||
@@ -317,6 +324,7 @@ namespace BTCPayServer.Tests
|
||||
Assert.Equal(Money.Coins(1.3m), accounting.TotalDue);
|
||||
|
||||
entity = new InvoiceEntity();
|
||||
entity.Networks = networkProvider;
|
||||
entity.ProductInformation = new ProductInformation() {Price = 5000};
|
||||
PaymentMethodDictionary paymentMethods = new PaymentMethodDictionary();
|
||||
paymentMethods.Add(
|
||||
@@ -445,6 +453,7 @@ namespace BTCPayServer.Tests
|
||||
new LightningLikePaymentHandler(null, null, networkProvider, null),
|
||||
});
|
||||
var entity = new InvoiceEntity();
|
||||
entity.Networks = networkProvider;
|
||||
#pragma warning disable CS0618
|
||||
entity.Payments = new List<PaymentEntity>();
|
||||
entity.SetPaymentMethod(new PaymentMethod()
|
||||
|
||||
@@ -84,7 +84,7 @@ services:
|
||||
- "32838"
|
||||
environment:
|
||||
NBXPLORER_NETWORK: regtest
|
||||
NBXPLORER_CHAINS: "btc,ltc"
|
||||
NBXPLORER_CHAINS: "btc,ltc,lbtc"
|
||||
NBXPLORER_BTCRPCURL: http://bitcoind:43782/
|
||||
NBXPLORER_BTCNODEENDPOINT: bitcoind:39388
|
||||
NBXPLORER_BTCRPCUSER: ceiwHEbqWI83
|
||||
@@ -93,12 +93,17 @@ services:
|
||||
NBXPLORER_LTCNODEENDPOINT: litecoind:39388
|
||||
NBXPLORER_LTCRPCUSER: ceiwHEbqWI83
|
||||
NBXPLORER_LTCRPCPASSWORD: DwubwWsoo3
|
||||
NBXPLORER_LBTCRPCURL: "http://elementsd-liquid:19332/"
|
||||
NBXPLORER_LBTCNODEENDPOINT: "elementsd-liquid:19444"
|
||||
NBXPLORER_LBTCRPCUSER: "liquid"
|
||||
NBXPLORER_LBTCRPCPASSWORD: "liquid"
|
||||
NBXPLORER_BIND: 0.0.0.0:32838
|
||||
NBXPLORER_VERBOSE: 1
|
||||
NBXPLORER_NOAUTH: 1
|
||||
links:
|
||||
- bitcoind
|
||||
- litecoind
|
||||
- elementsd-liquid
|
||||
|
||||
|
||||
bitcoind:
|
||||
@@ -216,6 +221,34 @@ services:
|
||||
- "43782" # RPC
|
||||
- "39388" # P2P
|
||||
|
||||
elementsd-liquid:
|
||||
restart: always
|
||||
container_name: btcpayserver_elementsd_liquid
|
||||
image: btcpayserver/elements:0.18.1.1-1
|
||||
environment:
|
||||
ELEMENTS_CHAIN: elementsregtest
|
||||
ELEMENTS_EXTRA_ARGS: |
|
||||
mainchainrpcport=43782
|
||||
mainchainrpchost=bitcoind
|
||||
mainchainrpcuser=liquid
|
||||
mainchainrpcpassword=liquid
|
||||
rpcport=19332
|
||||
rpcbind=0.0.0.0:19332
|
||||
rpcauth=liquid:c8bf1a8961d97f224cb21224aaa8235d$$402f4a8907683d057b8c58a42940b6e54d1638322a42986ae28ebb844e603ae6
|
||||
port=19444
|
||||
whitelist=0.0.0.0/0
|
||||
validatepegin=0
|
||||
initialfreecoins=210000000000000
|
||||
con_dyna_deploy_start=99999999999
|
||||
expose:
|
||||
- "19332"
|
||||
- "19444"
|
||||
ports:
|
||||
- "19332:19332"
|
||||
- "19444:19444"
|
||||
volumes:
|
||||
- "elementsd_liquid_datadir:/data"
|
||||
|
||||
postgres:
|
||||
image: postgres:9.6.5
|
||||
ports:
|
||||
@@ -287,6 +320,7 @@ services:
|
||||
volumes:
|
||||
sshd_datadir:
|
||||
bitcoin_datadir:
|
||||
elementsd_liquid_datadir:
|
||||
customer_lightningd_datadir:
|
||||
merchant_lightningd_datadir:
|
||||
lightning_charge_datadir:
|
||||
|
||||
@@ -86,8 +86,16 @@ namespace BTCPayServer.Configuration
|
||||
|
||||
var supportedChains = conf.GetOrDefault<string>("chains", "btc")
|
||||
.Split(',', StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(t => t.ToUpperInvariant());
|
||||
NetworkProvider = new BTCPayNetworkProvider(NetworkType).Filter(supportedChains.ToArray());
|
||||
.Select(t => t.ToUpperInvariant()).ToList();
|
||||
|
||||
var networkProvider = new BTCPayNetworkProvider(NetworkType);
|
||||
var filtered = networkProvider.Filter(supportedChains.ToArray());
|
||||
var elementsBased = filtered.GetAll().OfType<ElementsBTCPayNetwork>();
|
||||
var parentChains = elementsBased.Select(network => network.NetworkCryptoCode.ToUpperInvariant()).Distinct();
|
||||
var allSubChains = networkProvider.GetAll().OfType<ElementsBTCPayNetwork>()
|
||||
.Where(network => parentChains.Contains(network.NetworkCryptoCode)).Select(network => network.CryptoCode);
|
||||
supportedChains.AddRange(allSubChains);
|
||||
NetworkProvider = networkProvider.Filter(supportedChains.ToArray());
|
||||
foreach (var chain in supportedChains)
|
||||
{
|
||||
if (NetworkProvider.GetNetwork<BTCPayNetworkBase>(chain) == null)
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace BTCPayServer.Controllers
|
||||
var getxpubResult = new GetXPubs();
|
||||
getxpubResult.ExtPubKey = await hw.GetExtPubKey(network, k, normalOperationTimeout.Token);
|
||||
var segwit = network.NBitcoinNetwork.Consensus.SupportSegwit;
|
||||
var derivation = new DerivationStrategyFactory(network.NBitcoinNetwork).CreateDirectDerivationStrategy(getxpubResult.ExtPubKey, new DerivationStrategyOptions()
|
||||
var derivation = network.NBXplorerNetwork.DerivationStrategyFactory.CreateDirectDerivationStrategy(getxpubResult.ExtPubKey, new DerivationStrategyOptions()
|
||||
{
|
||||
ScriptPubKeyType = segwit ? ScriptPubKeyType.SegwitP2SH : ScriptPubKeyType.Legacy
|
||||
});
|
||||
@@ -374,7 +374,8 @@ namespace BTCPayServer.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
private IActionResult ShowAddresses(DerivationSchemeViewModel vm, DerivationSchemeSettings strategy)
|
||||
private IActionResult
|
||||
ShowAddresses(DerivationSchemeViewModel vm, DerivationSchemeSettings strategy)
|
||||
{
|
||||
vm.DerivationScheme = strategy.AccountDerivation.ToString();
|
||||
var deposit = new NBXplorer.KeyPathTemplates(null).GetKeyPathTemplate(DerivationFeature.Deposit);
|
||||
@@ -386,8 +387,11 @@ namespace BTCPayServer.Controllers
|
||||
{
|
||||
var keyPath = deposit.GetKeyPath((uint)i);
|
||||
var rootedKeyPath = vm.GetAccountKeypath()?.Derive(keyPath);
|
||||
var address = line.Derive((uint)i);
|
||||
vm.AddressSamples.Add((keyPath.ToString(), address.ScriptPubKey.GetDestinationAddress(strategy.Network.NBitcoinNetwork).ToString(), rootedKeyPath));
|
||||
var derivation = line.Derive((uint)i);
|
||||
var address = strategy.Network.NBXplorerNetwork.CreateAddress(strategy.AccountDerivation,
|
||||
line.KeyPathTemplate.GetKeyPath((uint)i),
|
||||
derivation.ScriptPubKey).ToString();
|
||||
vm.AddressSamples.Add((keyPath.ToString(), address, rootedKeyPath));
|
||||
}
|
||||
}
|
||||
vm.Confirmation = true;
|
||||
|
||||
@@ -479,12 +479,12 @@ namespace BTCPayServer.Controllers
|
||||
store
|
||||
.GetSupportedPaymentMethods(_NetworkProvider)
|
||||
.OfType<DerivationSchemeSettings>()
|
||||
.ToDictionary(c => c.Network.CryptoCode);
|
||||
.ToDictionary(c => c.Network.CryptoCode.ToUpperInvariant());
|
||||
|
||||
var lightningByCryptoCode = store
|
||||
.GetSupportedPaymentMethods(_NetworkProvider)
|
||||
.OfType<LightningSupportedPaymentMethod>()
|
||||
.ToDictionary(c => c.CryptoCode);
|
||||
.ToDictionary(c => c.CryptoCode.ToUpperInvariant());
|
||||
|
||||
foreach (var paymentMethodId in _paymentMethodHandlerDictionary.Distinct().SelectMany(handler => handler.GetSupportedPaymentMethods()))
|
||||
{
|
||||
@@ -492,9 +492,11 @@ namespace BTCPayServer.Controllers
|
||||
{
|
||||
case BitcoinPaymentType _:
|
||||
var strategy = derivationByCryptoCode.TryGet(paymentMethodId.CryptoCode);
|
||||
var network = _NetworkProvider.GetNetwork<BTCPayNetwork>(paymentMethodId.CryptoCode);
|
||||
vm.DerivationSchemes.Add(new StoreViewModel.DerivationScheme()
|
||||
{
|
||||
Crypto = paymentMethodId.CryptoCode,
|
||||
WalletSupported = network.WalletSupported,
|
||||
Value = strategy?.ToPrettyString() ?? string.Empty,
|
||||
WalletId = new WalletId(store.Id, paymentMethodId.CryptoCode),
|
||||
Enabled = !excludeFilters.Match(paymentMethodId) && strategy != null
|
||||
|
||||
@@ -202,7 +202,7 @@ namespace BTCPayServer.Controllers
|
||||
.Select(d => ((Wallet: _walletProvider.GetWallet(d.Network),
|
||||
DerivationStrategy: d.AccountDerivation,
|
||||
Network: d.Network)))
|
||||
.Where(_ => _.Wallet != null)
|
||||
.Where(_ => _.Wallet != null && _.Network.WalletSupported)
|
||||
.Select(_ => (Wallet: _.Wallet,
|
||||
Store: s,
|
||||
Balance: GetBalanceString(_.Wallet, _.DerivationStrategy),
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using NBitcoin;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
using NBXplorer.DerivationStrategy;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using static BTCPayServer.Data.PaymentRequestData;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ using BTCPayServer.Security;
|
||||
using BTCPayServer.Services.Rates;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
using NBXplorer.DerivationStrategy;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace BTCPayServer.Data
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace BTCPayServer
|
||||
if (type == DerivationType.Legacy)
|
||||
return new DirectDerivationStrategy(extPubKey) { Segwit = false };
|
||||
if (type == DerivationType.SegwitP2SH)
|
||||
return new DerivationStrategyFactory(Network).Parse(extPubKey.ToString() + "-[p2sh]");
|
||||
return BtcPayNetwork.NBXplorerNetwork.DerivationStrategyFactory.Parse(extPubKey.ToString() + "-[p2sh]");
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace BTCPayServer
|
||||
|
||||
try
|
||||
{
|
||||
var result = new DerivationStrategyFactory(Network).Parse(str);
|
||||
var result = BtcPayNetwork.NBXplorerNetwork.DerivationStrategyFactory.Parse(str);
|
||||
return FindMatch(hintedLabels, result);
|
||||
}
|
||||
catch
|
||||
@@ -150,12 +150,11 @@ namespace BTCPayServer
|
||||
str = $"{str}-[{label}]";
|
||||
}
|
||||
|
||||
return FindMatch(hintedLabels, new DerivationStrategyFactory(Network).Parse(str));
|
||||
return FindMatch(hintedLabels, BtcPayNetwork.NBXplorerNetwork.DerivationStrategyFactory.Parse(str));
|
||||
}
|
||||
|
||||
private DerivationStrategyBase FindMatch(HashSet<string> hintLabels, DerivationStrategyBase result)
|
||||
{
|
||||
var facto = new DerivationStrategyFactory(Network);
|
||||
var firstKeyPath = new KeyPath("0/0");
|
||||
if (HintScriptPubKey == null)
|
||||
return result;
|
||||
@@ -169,7 +168,7 @@ namespace BTCPayServer
|
||||
resultNoLabels = string.Join('-', resultNoLabels.Split('-').Where(p => !IsLabel(p)));
|
||||
foreach (var labels in ItemCombinations(hintLabels.ToList()))
|
||||
{
|
||||
var hinted = facto.Parse(resultNoLabels + '-' + string.Join('-', labels.Select(l => $"[{l}]").ToArray()));
|
||||
var hinted = BtcPayNetwork.NBXplorerNetwork.DerivationStrategyFactory.Parse(resultNoLabels + '-' + string.Join('-', labels.Select(l => $"[{l}]").ToArray()));
|
||||
if (HintScriptPubKey == hinted.GetDerivation(firstKeyPath).ScriptPubKey)
|
||||
return hinted;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace BTCPayServer
|
||||
throw new ArgumentNullException(nameof(network));
|
||||
if (derivationStrategy == null)
|
||||
throw new ArgumentNullException(nameof(derivationStrategy));
|
||||
var result = new NBXplorer.DerivationStrategy.DerivationStrategyFactory(network.NBitcoinNetwork).Parse(derivationStrategy);
|
||||
var result = network.NBXplorerNetwork.DerivationStrategyFactory.Parse(derivationStrategy);
|
||||
return new DerivationSchemeSettings(result, network) { AccountOriginal = derivationStrategy.Trim() };
|
||||
}
|
||||
|
||||
|
||||
@@ -33,23 +33,24 @@ namespace BTCPayServer
|
||||
Logs.Configuration.LogInformation($"{setting.CryptoCode}: Cookie file is {(setting.CookieFile ?? "not set")}");
|
||||
if (setting.ExplorerUri != null)
|
||||
{
|
||||
_Clients.TryAdd(setting.CryptoCode, CreateExplorerClient(httpClientFactory.CreateClient(nameof(ExplorerClientProvider)), _NetworkProviders.GetNetwork<BTCPayNetwork>(setting.CryptoCode), setting.ExplorerUri, setting.CookieFile));
|
||||
_Clients.TryAdd(setting.CryptoCode.ToUpperInvariant(), CreateExplorerClient(httpClientFactory.CreateClient(nameof(ExplorerClientProvider)), _NetworkProviders.GetNetwork<BTCPayNetwork>(setting.CryptoCode), setting.ExplorerUri, setting.CookieFile));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ExplorerClient CreateExplorerClient(HttpClient httpClient, BTCPayNetwork n, Uri uri, string cookieFile)
|
||||
{
|
||||
var explorer = new ExplorerClient(n.NBXplorerNetwork, uri);
|
||||
|
||||
var explorer = n.NBXplorerNetwork.CreateExplorerClient(uri);
|
||||
explorer.SetClient(httpClient);
|
||||
if (cookieFile == null)
|
||||
{
|
||||
Logs.Configuration.LogWarning($"{n.CryptoCode}: Not using cookie authentication");
|
||||
Logs.Configuration.LogWarning($"{explorer.CryptoCode}: Not using cookie authentication");
|
||||
explorer.SetNoAuth();
|
||||
}
|
||||
if(!explorer.SetCookieAuth(cookieFile))
|
||||
{
|
||||
Logs.Configuration.LogWarning($"{n.CryptoCode}: Using cookie auth against NBXplorer, but {cookieFile} is not found");
|
||||
Logs.Configuration.LogWarning($"{explorer.CryptoCode}: Using cookie auth against NBXplorer, but {cookieFile} is not found");
|
||||
}
|
||||
return explorer;
|
||||
}
|
||||
@@ -61,7 +62,7 @@ namespace BTCPayServer
|
||||
var network = _NetworkProviders.GetNetwork<BTCPayNetwork>(cryptoCode);
|
||||
if (network == null)
|
||||
return null;
|
||||
_Clients.TryGetValue(network.CryptoCode, out ExplorerClient client);
|
||||
_Clients.TryGetValue(network.NBXplorerNetwork.CryptoCode, out ExplorerClient client);
|
||||
return client;
|
||||
}
|
||||
|
||||
@@ -79,6 +80,7 @@ namespace BTCPayServer
|
||||
|
||||
public bool IsAvailable(string cryptoCode)
|
||||
{
|
||||
cryptoCode = cryptoCode.ToUpperInvariant();
|
||||
return _Clients.ContainsKey(cryptoCode) && _Dashboard.IsFullySynched(cryptoCode, out var unused);
|
||||
}
|
||||
|
||||
@@ -87,7 +89,7 @@ namespace BTCPayServer
|
||||
var network = _NetworkProviders.GetNetwork<BTCPayNetwork>(cryptoCode);
|
||||
if (network == null)
|
||||
return null;
|
||||
if (_Clients.ContainsKey(network.CryptoCode))
|
||||
if (_Clients.ContainsKey(network.NBXplorerNetwork.CryptoCode))
|
||||
return network;
|
||||
return null;
|
||||
}
|
||||
@@ -96,7 +98,7 @@ namespace BTCPayServer
|
||||
{
|
||||
foreach (var net in _NetworkProviders.GetAll().OfType<BTCPayNetwork>())
|
||||
{
|
||||
if (_Clients.TryGetValue(net.CryptoCode, out ExplorerClient explorer))
|
||||
if (_Clients.TryGetValue(net.NBXplorerNetwork.CryptoCode, out ExplorerClient explorer))
|
||||
{
|
||||
yield return (net, explorer);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using NBitcoin;
|
||||
using NBXplorer;
|
||||
|
||||
namespace BTCPayServer
|
||||
{
|
||||
@@ -11,19 +14,27 @@ namespace BTCPayServer
|
||||
{
|
||||
case Money money:
|
||||
return money.ToDecimal(MoneyUnit.BTC);
|
||||
// case MoneyBag mb:
|
||||
// return mb.Select(money => money.GetValue(network)).Sum();
|
||||
// case AssetMoney assetMoney:
|
||||
// if (network is ElementsBTCPayNetwork elementsBTCPayNetwork)
|
||||
// {
|
||||
// return elementsBTCPayNetwork.AssetId == assetMoney.AssetId
|
||||
// ? new Money(assetMoney.Quantity)
|
||||
// : Money.Zero;
|
||||
// }
|
||||
// throw new NotSupportedException("IMoney type not supported");
|
||||
case MoneyBag mb:
|
||||
return mb.Select(money => money.GetValue(network)).Sum();
|
||||
case AssetMoney assetMoney:
|
||||
if (network is ElementsBTCPayNetwork elementsBTCPayNetwork)
|
||||
{
|
||||
return elementsBTCPayNetwork.AssetId == assetMoney.AssetId
|
||||
? Convert(assetMoney.Quantity, elementsBTCPayNetwork.Divisibility)
|
||||
: 0;
|
||||
}
|
||||
throw new NotSupportedException("IMoney type not supported");
|
||||
default:
|
||||
throw new NotSupportedException("IMoney type not supported");
|
||||
}
|
||||
}
|
||||
|
||||
public static decimal Convert(long sats, int divisibility = 8)
|
||||
{
|
||||
var amt = sats.ToString(CultureInfo.InvariantCulture).PadLeft(divisibility, '0');
|
||||
amt = amt.Length == divisibility ? $"0.{amt}" : amt.Insert(amt.Length - divisibility, ".");
|
||||
|
||||
return decimal.Parse(amt, CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace BTCPayServer.HostedServices
|
||||
public void Publish(BTCPayNetworkBase network, NBXplorerState state, StatusResult status, string error)
|
||||
{
|
||||
var summary = new NBXplorerSummary() { Network = network, State = state, Status = status, Error = error };
|
||||
_Summaries.AddOrUpdate(network.CryptoCode, summary, (k, v) => summary);
|
||||
_Summaries.AddOrUpdate(network.CryptoCode.ToUpperInvariant(), summary, (k, v) => summary);
|
||||
}
|
||||
|
||||
public bool IsFullySynched()
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace BTCPayServer.ModelBinders
|
||||
var network = networkProvider.GetNetwork<BTCPayNetwork>(cryptoCode ?? "BTC");
|
||||
try
|
||||
{
|
||||
var data = new DerivationStrategyFactory(network.NBitcoinNetwork).Parse(key);
|
||||
var data =network.NBXplorerNetwork.DerivationStrategyFactory.Parse(key);
|
||||
if (!bindingContext.ModelType.IsInstanceOfType(data))
|
||||
{
|
||||
throw new FormatException("Invalid destination type");
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace BTCPayServer.Models.StoreViewModels
|
||||
public string Crypto { get; set; }
|
||||
public string Value { get; set; }
|
||||
public WalletId WalletId { get; set; }
|
||||
public bool WalletSupported { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -20,10 +20,12 @@ namespace BTCPayServer.Payments.Bitcoin
|
||||
{
|
||||
|
||||
}
|
||||
public BitcoinLikePaymentData(TxOut txout, OutPoint outpoint, bool rbf)
|
||||
|
||||
public BitcoinLikePaymentData(BitcoinAddress address, IMoney value, OutPoint outpoint, bool rbf)
|
||||
{
|
||||
Address = address;
|
||||
Value = value;
|
||||
Outpoint = outpoint;
|
||||
Output = txout;
|
||||
ConfirmationCount = 0;
|
||||
RBF = rbf;
|
||||
}
|
||||
@@ -36,6 +38,17 @@ namespace BTCPayServer.Payments.Bitcoin
|
||||
public int ConfirmationCount { get; set; }
|
||||
public bool RBF { get; set; }
|
||||
public decimal NetworkFee { get; set; }
|
||||
public BitcoinAddress Address { get; set; }
|
||||
public IMoney Value { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public Script ScriptPubKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return Address?.ScriptPubKey ?? Output.ScriptPubKey;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is set to true if the payment was created before CryptoPaymentData existed in BTCPayServer
|
||||
@@ -54,7 +67,7 @@ namespace BTCPayServer.Payments.Bitcoin
|
||||
|
||||
public decimal GetValue()
|
||||
{
|
||||
return Output.Value.ToDecimal(MoneyUnit.BTC);
|
||||
return Value?.GetValue(Network as BTCPayNetwork)??Output.Value.ToDecimal(MoneyUnit.BTC);
|
||||
}
|
||||
|
||||
public bool PaymentCompleted(PaymentEntity entity)
|
||||
@@ -85,7 +98,7 @@ namespace BTCPayServer.Payments.Bitcoin
|
||||
|
||||
public BitcoinAddress GetDestination()
|
||||
{
|
||||
return Output.ScriptPubKey.GetDestinationAddress(((BTCPayNetwork)Network).NBitcoinNetwork);
|
||||
return Address?? Output.ScriptPubKey.GetDestinationAddress(((BTCPayNetwork)Network).NBitcoinNetwork);
|
||||
}
|
||||
|
||||
string CryptoPaymentData.GetDestination()
|
||||
|
||||
@@ -18,6 +18,7 @@ using NBitcoin;
|
||||
using NBXplorer.Models;
|
||||
using BTCPayServer.Payments;
|
||||
using BTCPayServer.HostedServices;
|
||||
using NBitcoin.Altcoins.Elements;
|
||||
|
||||
#if NETCOREAPP21
|
||||
using IHostApplicationLifetime = Microsoft.AspNetCore.Hosting.IApplicationLifetime;
|
||||
@@ -148,16 +149,15 @@ namespace BTCPayServer.Payments.Bitcoin
|
||||
break;
|
||||
case NBXplorer.Models.NewTransactionEvent evt:
|
||||
wallet.InvalidateCache(evt.DerivationStrategy);
|
||||
foreach (var output in evt.Outputs)
|
||||
foreach (var output in network.GetValidOutputs(evt))
|
||||
{
|
||||
foreach (var txCoin in evt.TransactionData.Transaction.Outputs.AsCoins()
|
||||
.Where(o => o.ScriptPubKey == output.ScriptPubKey))
|
||||
{
|
||||
var key = output.ScriptPubKey.Hash + "#" + network.CryptoCode;
|
||||
var key = output.Item1.ScriptPubKey.Hash + "#" + network.CryptoCode.ToUpperInvariant();
|
||||
var invoice = (await _InvoiceRepository.GetInvoicesFromAddresses(new [] {key})).FirstOrDefault();
|
||||
if (invoice != null)
|
||||
{
|
||||
var paymentData = new BitcoinLikePaymentData(txCoin.TxOut, txCoin.Outpoint, evt.TransactionData.Transaction.RBF);
|
||||
var address = network.NBXplorerNetwork.CreateAddress(evt.DerivationStrategy,
|
||||
output.Item1.KeyPath, output.Item1.ScriptPubKey);
|
||||
var paymentData = new BitcoinLikePaymentData(address, output.matchedOutput.Value, output.outPoint, evt.TransactionData.Transaction.RBF);
|
||||
var alreadyExist = GetAllBitcoinPaymentData(invoice).Where(c => c.GetPaymentId() == paymentData.GetPaymentId()).Any();
|
||||
if (!alreadyExist)
|
||||
{
|
||||
@@ -170,7 +170,7 @@ namespace BTCPayServer.Payments.Bitcoin
|
||||
await UpdatePaymentStates(wallet, invoice.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -316,7 +316,7 @@ namespace BTCPayServer.Payments.Bitcoin
|
||||
return new TransactionConflicts(conflictsByOutpoint.Where(c => c.Value.Transactions.Count > 1).Select(c => c.Value));
|
||||
}
|
||||
|
||||
private async Task<int> FindPaymentViaPolling(BTCPayWallet wallet, BTCPayNetworkBase network)
|
||||
private async Task<int> FindPaymentViaPolling(BTCPayWallet wallet, BTCPayNetwork network)
|
||||
{
|
||||
int totalPayment = 0;
|
||||
var invoices = await _InvoiceRepository.GetPendingInvoices();
|
||||
@@ -333,14 +333,18 @@ namespace BTCPayServer.Payments.Bitcoin
|
||||
if (!invoice.Support(cryptoId))
|
||||
continue;
|
||||
var coins = (await wallet.GetUnspentCoins(strategy))
|
||||
.Where(c => invoice.AvailableAddressHashes.Contains(c.Coin.ScriptPubKey.Hash.ToString() + cryptoId))
|
||||
.Where(c => invoice.AvailableAddressHashes.Contains(c.ScriptPubKey.Hash.ToString() + cryptoId))
|
||||
.ToArray();
|
||||
foreach (var coin in coins.Where(c => !alreadyAccounted.Contains(c.Coin.Outpoint)))
|
||||
foreach (var coin in coins.Where(c => !alreadyAccounted.Contains(c.OutPoint)))
|
||||
{
|
||||
var transaction = await wallet.GetTransactionAsync(coin.Coin.Outpoint.Hash);
|
||||
var paymentData = new BitcoinLikePaymentData(coin.Coin.TxOut, coin.Coin.Outpoint, transaction.Transaction.RBF);
|
||||
var transaction = await wallet.GetTransactionAsync(coin.OutPoint.Hash);
|
||||
|
||||
var address = network.NBXplorerNetwork.CreateAddress(strategy, coin.KeyPath, coin.ScriptPubKey);
|
||||
var paymentData = new BitcoinLikePaymentData(address, coin.Value, coin.OutPoint,
|
||||
transaction.Transaction.RBF);
|
||||
|
||||
var payment = await _InvoiceRepository.AddPayment(invoice.Id, coin.Timestamp, paymentData, network).ConfigureAwait(false);
|
||||
alreadyAccounted.Add(coin.Coin.Outpoint);
|
||||
alreadyAccounted.Add(coin.OutPoint);
|
||||
if (payment != null)
|
||||
{
|
||||
invoice = await ReceivedPayment(wallet, invoice, payment, strategy);
|
||||
@@ -369,7 +373,7 @@ namespace BTCPayServer.Payments.Bitcoin
|
||||
var paymentMethod = invoice.GetPaymentMethod(wallet.Network, PaymentTypes.BTCLike);
|
||||
if (paymentMethod != null &&
|
||||
paymentMethod.GetPaymentMethodDetails() is BitcoinLikeOnChainPaymentMethod btc &&
|
||||
btc.GetDepositAddress(wallet.Network.NBitcoinNetwork).ScriptPubKey == paymentData.Output.ScriptPubKey &&
|
||||
btc.GetDepositAddress(wallet.Network.NBitcoinNetwork).ScriptPubKey == paymentData.ScriptPubKey &&
|
||||
paymentMethod.Calculate().Due > Money.Zero)
|
||||
{
|
||||
var address = await wallet.ReserveAddressAsync(strategy);
|
||||
|
||||
@@ -21,9 +21,14 @@ namespace BTCPayServer.Payments
|
||||
public override string ToPrettyString() => "On-Chain";
|
||||
public override string GetId() => "BTCLike";
|
||||
|
||||
public override CryptoPaymentData DeserializePaymentData(string str)
|
||||
public override CryptoPaymentData DeserializePaymentData(BTCPayNetworkBase network, string str)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<BitcoinLikePaymentData>(str);
|
||||
return ((BTCPayNetwork) network).ToObject<BitcoinLikePaymentData>(str);
|
||||
}
|
||||
|
||||
public override string SerializePaymentData(BTCPayNetworkBase network, CryptoPaymentData paymentData)
|
||||
{
|
||||
return ((BTCPayNetwork) network).ToString(paymentData);
|
||||
}
|
||||
|
||||
public override IPaymentMethodDetails DeserializePaymentMethodDetails(string str)
|
||||
|
||||
@@ -19,10 +19,14 @@ namespace BTCPayServer.Payments
|
||||
|
||||
public override string ToPrettyString() => "Off-Chain";
|
||||
public override string GetId() => "LightningLike";
|
||||
|
||||
public override CryptoPaymentData DeserializePaymentData(string str)
|
||||
public override CryptoPaymentData DeserializePaymentData(BTCPayNetworkBase network, string str)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<Payments.Lightning.LightningLikePaymentData>(str);
|
||||
return ((BTCPayNetwork) network).ToObject<LightningLikePaymentData>(str);
|
||||
}
|
||||
|
||||
public override string SerializePaymentData(BTCPayNetworkBase network, CryptoPaymentData paymentData)
|
||||
{
|
||||
return ((BTCPayNetwork) network).ToString(paymentData);
|
||||
}
|
||||
|
||||
public override IPaymentMethodDetails DeserializePaymentMethodDetails(string str)
|
||||
|
||||
@@ -60,7 +60,8 @@ namespace BTCPayServer.Payments
|
||||
}
|
||||
|
||||
public abstract string GetId();
|
||||
public abstract CryptoPaymentData DeserializePaymentData(string str);
|
||||
public abstract CryptoPaymentData DeserializePaymentData(BTCPayNetworkBase network, string str);
|
||||
public abstract string SerializePaymentData(BTCPayNetworkBase network, CryptoPaymentData paymentData);
|
||||
public abstract IPaymentMethodDetails DeserializePaymentMethodDetails(string str);
|
||||
public abstract ISupportedPaymentMethod DeserializeSupportedPaymentMethod(BTCPayNetworkBase network, JToken value);
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"BTCPAY_HttpsUseDefaultCertificate": "true",
|
||||
"BTCPAY_BUNDLEJSCSS": "false",
|
||||
"BTCPAY_LTCEXPLORERURL": "http://127.0.0.1:32838/",
|
||||
"BTCPAY_LBTCEXPLORERURL": "http://127.0.0.1:32838/",
|
||||
"BTCPAY_BTCLIGHTNING": "type=charge;server=http://127.0.0.1:54938/;api-token=foiewnccewuify",
|
||||
"BTCPAY_BTCEXTERNALLNDGRPC": "type=lnd-grpc;server=https://lnd:lnd@127.0.0.1:53280/;allowinsecure=true",
|
||||
"BTCPAY_BTCEXTERNALLNDREST": "type=lnd-rest;server=https://lnd:lnd@127.0.0.1:53280/lnd-rest/btc/;allowinsecure=true",
|
||||
@@ -43,7 +44,7 @@
|
||||
"BTCPAY_ALLOW-ADMIN-REGISTRATION": "true",
|
||||
"BTCPAY_DISABLE-REGISTRATION": "false",
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"BTCPAY_CHAINS": "btc,ltc",
|
||||
"BTCPAY_CHAINS": "btc,lbtc",
|
||||
"BTCPAY_POSTGRES": "User ID=postgres;Host=127.0.0.1;Port=39372;Database=btcpayserver",
|
||||
"BTCPAY_EXTERNALSERVICES": "totoservice:totolink;",
|
||||
"BTCPAY_SSHCONNECTION": "root@127.0.0.1:21622",
|
||||
|
||||
@@ -14,12 +14,14 @@ namespace BTCPayServer.Services.Altcoins.Monero.Payments
|
||||
public override string GetId()=> "MoneroLike";
|
||||
|
||||
|
||||
public override CryptoPaymentData DeserializePaymentData(string str)
|
||||
public override CryptoPaymentData DeserializePaymentData(BTCPayNetworkBase network, string str)
|
||||
{
|
||||
|
||||
#pragma warning disable CS0618
|
||||
return JsonConvert.DeserializeObject<MoneroLikePaymentData>(str);
|
||||
#pragma warning restore CS0618
|
||||
}
|
||||
|
||||
public override string SerializePaymentData(BTCPayNetworkBase network, CryptoPaymentData paymentData)
|
||||
{
|
||||
return JsonConvert.SerializeObject(paymentData);
|
||||
}
|
||||
|
||||
public override IPaymentMethodDetails DeserializePaymentMethodDetails(string str)
|
||||
|
||||
@@ -562,8 +562,6 @@ namespace BTCPayServer.Services.Invoices
|
||||
return paymentMethods;
|
||||
}
|
||||
|
||||
Network Dummy = Network.Main;
|
||||
|
||||
public void SetPaymentMethod(PaymentMethod paymentMethod)
|
||||
{
|
||||
var dict = GetPaymentMethods();
|
||||
@@ -969,7 +967,7 @@ namespace BTCPayServer.Services.Invoices
|
||||
}
|
||||
else
|
||||
{
|
||||
paymentData = GetPaymentMethodId().PaymentType.DeserializePaymentData(CryptoPaymentData);
|
||||
paymentData = GetPaymentMethodId().PaymentType.DeserializePaymentData(Network,CryptoPaymentData);
|
||||
paymentData.Network = Network;
|
||||
if (paymentData is BitcoinLikePaymentData bitcoin)
|
||||
{
|
||||
@@ -991,7 +989,7 @@ namespace BTCPayServer.Services.Invoices
|
||||
///
|
||||
}
|
||||
CryptoPaymentDataType = cryptoPaymentData.GetPaymentType().ToString();
|
||||
CryptoPaymentData = JsonConvert.SerializeObject(cryptoPaymentData);
|
||||
CryptoPaymentData = GetPaymentMethodId().PaymentType.SerializePaymentData(Network,cryptoPaymentData);
|
||||
#pragma warning restore CS0618
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ using NBitpayClient;
|
||||
using Newtonsoft.Json;
|
||||
using System.Linq;
|
||||
using NBitcoin;
|
||||
using NBitcoin.DataEncoders;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Query;
|
||||
@@ -21,7 +20,10 @@ using BTCPayServer.Models.InvoicingModels;
|
||||
using BTCPayServer.Logging;
|
||||
using BTCPayServer.Payments;
|
||||
using System.Data.Common;
|
||||
using NBitcoin.Altcoins;
|
||||
using NBitcoin.Altcoins.Elements;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Encoders = NBitcoin.DataEncoders.Encoders;
|
||||
|
||||
namespace BTCPayServer.Services.Invoices
|
||||
{
|
||||
@@ -707,7 +709,7 @@ retry:
|
||||
PaymentData data = new PaymentData
|
||||
{
|
||||
Id = paymentData.GetPaymentId(),
|
||||
Blob = ToBytes(entity, network),
|
||||
Blob = ToBytes(entity, entity.Network),
|
||||
InvoiceDataId = invoiceId,
|
||||
Accounted = accounted
|
||||
};
|
||||
|
||||
@@ -18,9 +18,12 @@ namespace BTCPayServer.Services.Wallets
|
||||
{
|
||||
public class ReceivedCoin
|
||||
{
|
||||
public Coin Coin { get; set; }
|
||||
public Script ScriptPubKey { get; set; }
|
||||
public OutPoint OutPoint { get; set; }
|
||||
public DateTimeOffset Timestamp { get; set; }
|
||||
public KeyPath KeyPath { get; set; }
|
||||
public IMoney Value { get; set; }
|
||||
|
||||
}
|
||||
public class NetworkCoins
|
||||
{
|
||||
@@ -71,7 +74,8 @@ namespace BTCPayServer.Services.Wallets
|
||||
await _Client.TrackAsync(derivationStrategy).ConfigureAwait(false);
|
||||
pathInfo = await _Client.GetUnusedAsync(derivationStrategy, DerivationFeature.Deposit, 0, true).ConfigureAwait(false);
|
||||
}
|
||||
return pathInfo.ScriptPubKey.GetDestinationAddress(Network.NBitcoinNetwork);
|
||||
|
||||
return pathInfo.Address;
|
||||
}
|
||||
|
||||
public async Task<(BitcoinAddress, KeyPath)> GetChangeAddressAsync(DerivationStrategyBase derivationStrategy)
|
||||
@@ -173,9 +177,11 @@ namespace BTCPayServer.Services.Wallets
|
||||
.GetUnspentUTXOs()
|
||||
.Select(c => new ReceivedCoin()
|
||||
{
|
||||
Coin = c.AsCoin(derivationStrategy),
|
||||
KeyPath = c.KeyPath,
|
||||
Timestamp = c.Timestamp
|
||||
Value = c.Value,
|
||||
Timestamp = c.Timestamp,
|
||||
OutPoint = c.Outpoint,
|
||||
ScriptPubKey = c.ScriptPubKey
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace BTCPayServer.Services.Wallets
|
||||
var explorerClient = _Client.GetExplorerClient(network.CryptoCode);
|
||||
if (explorerClient == null)
|
||||
continue;
|
||||
_Wallets.Add(network.CryptoCode, new BTCPayWallet(explorerClient, new MemoryCache(_Options), network));
|
||||
_Wallets.Add(network.CryptoCode.ToUpperInvariant(), new BTCPayWallet(explorerClient, new MemoryCache(_Options), network));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace BTCPayServer.Services.Wallets
|
||||
{
|
||||
if (cryptoCode == null)
|
||||
throw new ArgumentNullException(nameof(cryptoCode));
|
||||
_Wallets.TryGetValue(cryptoCode, out var result);
|
||||
_Wallets.TryGetValue(cryptoCode.ToUpperInvariant(), out var result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
}
|
||||
</td>
|
||||
<td style="text-align:right">
|
||||
@if(!string.IsNullOrWhiteSpace(scheme.Value))
|
||||
@if(!string.IsNullOrWhiteSpace(scheme.Value) && scheme.WalletSupported)
|
||||
{
|
||||
<a asp-action="WalletTransactions" asp-controller="Wallets" asp-route-walletId="@scheme.WalletId">Wallet</a><span> - </span>
|
||||
}
|
||||
|
||||
1
BTCPayServer/wwwroot/imlegacy/liquid-tether.svg
Normal file
1
BTCPayServer/wwwroot/imlegacy/liquid-tether.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2000 2000" width="2000" height="2000"><path d="M1000,0c552.26,0,1000,447.74,1000,1000S1552.24,2000,1000,2000,0,1552.38,0,1000,447.68,0,1000,0" fill="#53ae94"/><path d="M1123.42,866.76V718H1463.6V491.34H537.28V718H877.5V866.64C601,879.34,393.1,934.1,393.1,999.7s208,120.36,484.4,133.14v476.5h246V1132.8c276-12.74,483.48-67.46,483.48-133s-207.48-120.26-483.48-133m0,225.64v-0.12c-6.94.44-42.6,2.58-122,2.58-63.48,0-108.14-1.8-123.88-2.62v0.2C633.34,1081.66,451,1039.12,451,988.22S633.36,894.84,877.62,884V1050.1c16,1.1,61.76,3.8,124.92,3.8,75.86,0,114-3.16,121-3.8V884c243.8,10.86,425.72,53.44,425.72,104.16s-182,93.32-425.72,104.18" fill="#fff"/></svg>
|
||||
|
After Width: | Height: | Size: 704 B |
34
BTCPayServer/wwwroot/imlegacy/liquid.svg
Normal file
34
BTCPayServer/wwwroot/imlegacy/liquid.svg
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="46px" height="46px" viewBox="0 0 46 46" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 52.4 (67378) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>nav_liquid</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<polygon id="path-1" points="0.0158064742 0.0331955923 14.9692374 0.0331955923 14.9692374 23.1732438 0.0158064742 23.1732438"></polygon>
|
||||
<polygon id="path-3" points="0 0.00852524856 15.3983916 0.00852524856 15.3983916 24.9311295 0 24.9311295"></polygon>
|
||||
</defs>
|
||||
<g id="nav_liquid" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Group-7">
|
||||
<circle id="Oval" fill="#0E726B" fill-rule="nonzero" cx="23" cy="23" r="23"></circle>
|
||||
<g id="Group-13" transform="translate(8.000000, 8.000000)">
|
||||
<path d="M6.89588843,9.41403581 C6.2560124,10.6619008 5.85174242,11.995854 5.69430441,13.3789807 C5.64210055,13.8386915 5.97364325,14.2552893 6.43376722,14.3077686 C6.46613636,14.311281 6.4982989,14.3131405 6.52956612,14.3131405 C6.53858815,14.3131405 6.54754132,14.3129339 6.55642562,14.3126584 C6.96896006,14.2992287 7.31524105,13.9793939 7.36200413,13.5686501 C7.49623278,12.3875207 7.84189394,11.2473003 8.38927686,10.1796694 C9.59113636,7.83476584 11.6381749,6.09695592 14.1532576,5.28641873 C16.6684091,4.47588154 19.3447176,4.69158402 21.6893457,5.89358127 C22.1315634,6.12030303 22.5589738,6.38118457 22.9598691,6.66926997 C23.3358333,6.93869146 23.8611777,6.85260331 24.1308747,6.47725895 C24.4007782,6.10143251 24.314759,5.57608815 23.9390014,5.3061157 C23.4701997,4.96947658 22.9709573,4.66472452 22.4551171,4.40026171 C16.7832851,1.49282369 9.80339532,3.74213499 6.89588843,9.41403581" id="Fill-1" fill="#FFFFFF"></path>
|
||||
<g id="Group-5" transform="translate(2.479339, 0.035675)">
|
||||
<mask id="mask-2" fill="white">
|
||||
<use xlink:href="#path-1"></use>
|
||||
</mask>
|
||||
<g id="Clip-4"></g>
|
||||
<path d="M2.68554408,22.6742769 C2.9097865,22.9886708 3.26977273,23.1732438 3.65475895,23.1732438 C3.66777548,23.1732438 3.68079201,23.1730372 3.69387741,23.172624 C3.92803719,23.1649793 4.1532438,23.0887397 4.34525482,22.9518939 C4.87934573,22.5708333 5.00386364,21.8262741 4.62280303,21.2923209 C2.31178375,18.0525826 1.76130165,13.8956956 3.15028237,10.1728306 C4.83148072,5.66532369 9.02376722,2.61897383 13.8305165,2.41167355 C14.4860262,2.38343664 14.9963567,1.82716942 14.9681198,1.17165978 C14.9401584,0.52303719 14.3899518,0.0144283747 13.7404339,0.0337121212 L13.7281061,0.0341942149 C7.96412534,0.282679063 2.93685262,3.93591598 0.920599174,9.34108127 C-0.744896694,13.8057507 -0.0851170799,18.790186 2.68554408,22.6742769" id="Fill-3" fill="#FFFFFF" mask="url(#mask-2)"></path>
|
||||
</g>
|
||||
<g id="Group-8" transform="translate(0.000000, 5.889669)">
|
||||
<mask id="mask-4" fill="white">
|
||||
<use xlink:href="#path-3"></use>
|
||||
</mask>
|
||||
<g id="Clip-7"></g>
|
||||
<path d="M14.6429477,23.2208678 C8.29411846,22.5359504 3.19763085,17.7794766 1.96092287,11.3850551 C1.29294766,7.93181818 1.85782369,4.34586777 3.55169421,1.28774105 C3.77903581,0.877203857 3.63564738,0.353719008 3.23206612,0.120798898 C3.03674931,0.00805785124 2.80975207,-0.0210055096 2.59336088,0.0391873278 C2.37428375,0.1 2.19232782,0.244214876 2.08096419,0.445316804 C0.190399449,3.85853994 -0.440247934,7.86060606 0.305206612,11.7141185 C1.68557851,18.8517906 7.37655647,24.1613636 14.4666391,24.9265152 C14.4958402,24.9296143 14.5255234,24.9311295 14.5552755,24.9311295 C14.5647107,24.9311295 14.574146,24.9309917 14.5835813,24.9306474 C15.0021074,24.9169421 15.3504545,24.5870523 15.3937741,24.1633609 C15.4421212,23.693595 15.1052755,23.2708678 14.6429477,23.2208678" id="Fill-6" fill="#FFFFFF" mask="url(#mask-4)"></path>
|
||||
</g>
|
||||
<path d="M20.8919766,26.3926377 C19.749759,26.7185331 18.5809573,26.888781 17.4175275,26.8986295 C14.4131887,26.9374036 11.5654614,25.9904339 9.18729339,24.1626102 C9.00988292,24.0258333 8.78977273,23.9663292 8.56766529,23.9952548 C8.34514463,24.0241804 8.14727961,24.1382989 8.01043388,24.3163981 C7.7286157,24.6832025 7.79769284,25.2109573 8.16449725,25.4929132 C10.7931474,27.5135744 13.9281336,28.5781749 17.2434917,28.5781749 C17.3085055,28.5781749 17.3740014,28.5778306 17.4391529,28.5770041 C17.539084,28.575489 17.6386708,28.5732163 17.7383264,28.5700482 L17.7383953,28.5700482 C18.965668,28.5301722 20.1815771,28.3406405 21.352376,28.0067562 C21.7973485,27.879759 22.0560262,27.4144008 21.9290978,26.9694284 C21.8028581,26.5263843 21.3379132,26.2675689 20.8919766,26.3926377" id="Fill-9" fill="#FFFFFF"></path>
|
||||
<path d="M24.8857576,23.2102686 C24.7049036,22.8923623 24.2990496,22.7803788 23.9807989,22.9608196 C22.2428512,23.9473209 19.8861708,24.5384366 17.3449862,24.6251446 C16.9661295,24.6380234 16.6778375,24.9022796 16.659449,25.2535193 C16.6428512,25.5714256 16.8549725,25.8571006 17.1637879,25.9327204 L17.1638567,25.9327204 C17.203595,25.9425 17.2449862,25.9486983 17.2877548,25.9511088 C17.4449862,25.9593044 17.6055923,25.9633678 17.7691598,25.9633678 C19.9498072,25.9633678 22.6442287,25.2461501 24.6361019,24.1155028 C24.7903719,24.0280372 24.9012534,23.8856818 24.9484298,23.7146074 C24.9955372,23.5437397 24.973292,23.3646763 24.8857576,23.2102686" id="Fill-11" fill="#FFFFFF"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.5 KiB |
Reference in New Issue
Block a user